diff --git a/README.md b/README.md index 2354ae2..42168fd 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ please also make sure you're adding angular-sanitize.min.js. ngCsv attributes ---------------- -* ng-csv: The data array - Could be an expression, a value or a promise. +* ng-csv: The data array - Could be an expression, a value or a promise or an object(see multi-csv example). * filename: The filename that will be stored on the user's computer * csv-header: If provided, would use this attribute to create a header row @@ -62,6 +62,7 @@ ngCsv attributes * add-bom: Add the Byte Order Mark, use this option if you are getting an unexpected char when opening the file on any windows App. * charset: Defines the charset of the downloadable Csv file. Default is "utf-8". * csv-label: Defines whether or not using keys as csv column value (default is false). +* multi-csv: Set this to true if the data is an object which has arrays as values to create multiple table in a single csv file. ## Examples You can check out this live example here: https://asafdav.github.io/ng-csv/example/ diff --git a/build/ng-csv.js b/build/ng-csv.js index 80432ec..3122efc 100644 --- a/build/ng-csv.js +++ b/build/ng-csv.js @@ -36,17 +36,17 @@ if (typeof module !== 'undefined' && typeof exports !== 'undefined' && module.ex * Created by asafdav on 15/05/14. */ angular.module('ngCsv.services'). - service('CSV', ['$q', function ($q) { +service('CSV', ['$q', function($q) { var EOL = '\r\n'; var BOM = "\ufeff"; var specialChars = { - '\\t': '\t', - '\\b': '\b', - '\\v': '\v', - '\\f': '\f', - '\\r': '\r' + '\\t': '\t', + '\\b': '\b', + '\\v': '\v', + '\\f': '\f', + '\\r': '\r' }; /** @@ -55,30 +55,30 @@ angular.module('ngCsv.services'). * @param options * @returns {*} */ - this.stringifyField = function (data, options) { - if (options.decimalSep === 'locale' && this.isFloat(data)) { - return data.toLocaleString(); - } + this.stringifyField = function(data, options) { + if (options.decimalSep === 'locale' && this.isFloat(data)) { + return data.toLocaleString(); + } - if (options.decimalSep !== '.' && this.isFloat(data)) { - return data.toString().replace('.', options.decimalSep); - } + if (options.decimalSep !== '.' && this.isFloat(data)) { + return data.toString().replace('.', options.decimalSep); + } - if (typeof data === 'string') { - data = data.replace(/"/g, '""'); // Escape double qoutes + if (typeof data === 'string') { + data = data.replace(/"/g, '""'); // Escape double qoutes - if (options.quoteStrings || data.indexOf(',') > -1 || data.indexOf('\n') > -1 || data.indexOf('\r') > -1) { - data = options.txtDelim + data + options.txtDelim; - } + if (options.quoteStrings || data.indexOf(',') > -1 || data.indexOf('\n') > -1 || data.indexOf('\r') > -1) { + data = options.txtDelim + data + options.txtDelim; + } - return data; - } + return data; + } - if (typeof data === 'boolean') { - return data ? 'TRUE' : 'FALSE'; - } + if (typeof data === 'boolean') { + return data ? 'TRUE' : 'FALSE'; + } - return data; + return data; }; /** @@ -86,8 +86,8 @@ angular.module('ngCsv.services'). * @param input * @returns {boolean} */ - this.isFloat = function (input) { - return +input === input && (!isFinite(input) || Boolean(input % 1)); + this.isFloat = function(input) { + return +input === input && (!isFinite(input) || Boolean(input % 1)); }; /** @@ -99,82 +99,116 @@ angular.module('ngCsv.services'). * * addByteOrderMarker - Add Byte order mark, default(false) * @param callback */ - this.stringify = function (data, options) { - var def = $q.defer(); - - var that = this; - var csv = ""; - var csvContent = ""; - - var dataPromise = $q.when(data).then(function (responseData) { - //responseData = angular.copy(responseData);//moved to row creation - // Check if there's a provided header array - if (angular.isDefined(options.header) && options.header) { - var encodingArray, headerString; - - encodingArray = []; - angular.forEach(options.header, function (title, key) { - this.push(that.stringifyField(title, options)); - }, encodingArray); - - headerString = encodingArray.join(options.fieldSep ? options.fieldSep : ","); - csvContent += headerString + EOL; - } + this.stringify = function(data, options) { + var def = $q.defer(); - var arrData = []; + var that = this; + var csv = ""; + var csvContent = ""; - if (angular.isArray(responseData)) { - arrData = responseData; - } - else if (angular.isFunction(responseData)) { - arrData = responseData(); - } + var dataPromise = $q.when(data).then(function(responseData) { - // Check if using keys as labels - if (angular.isDefined(options.label) && options.label && typeof options.label === 'boolean') { - var labelArray, labelString; + var arrData = []; - labelArray = []; - angular.forEach(arrData[0], function(value, label) { - this.push(that.stringifyField(label, options)); - }, labelArray); - labelString = labelArray.join(options.fieldSep ? options.fieldSep : ","); - csvContent += labelString + EOL; - } + if (angular.isArray(responseData)) { + arrData = responseData; + } else if (angular.isFunction(responseData)) { + arrData = responseData(); + } else if (angular.isObject(responseData)) { + arrData = responseData; + } - angular.forEach(arrData, function (oldRow, index) { - var row = angular.copy(arrData[index]); - var dataString, infoArray; + // Check if needs to write multiple csv files + if (angular.isDefined(options.multiCsv) && options.multiCsv && typeof options.multiCsv === 'boolean') { + angular.forEach(arrData, function(val, key) { + csvContent += that.capitalize(key) + EOL; + JsonObjectToCSV(val, true,key); + csvContent += EOL; + }); + } else { + JsonObjectToCSV(arrData, false,""); + } - infoArray = []; + function addKeysColumnHeader(originData, multiCsv) { + // Check if using keys as labels + if (angular.isDefined(options.label) && options.label && typeof options.label === 'boolean') { + var labelArray, labelString, iterator; + + labelArray = []; + + if (multiCsv) { + iterator = !!options.columnOrder ? options.columnOrder : originData[0]; + } else { + iterator = !!options.columnOrder ? options.columnOrder : arrData[0]; + } + + angular.forEach(iterator, function(value, label) { + var val = !!options.columnOrder ? value : label; + this.push(that.stringifyField(val, options)); + }, labelArray); + labelString = labelArray.join(options.fieldSep ? options.fieldSep : ","); + csvContent += labelString + EOL; + } + } - var iterator = !!options.columnOrder ? options.columnOrder : row; - angular.forEach(iterator, function (field, key) { - var val = !!options.columnOrder ? row[field] : field; - this.push(that.stringifyField(val, options)); - }, infoArray); + function JsonObjectToCSV(originData, multiCsv,dataLabel) { + addHeader(dataLabel, multiCsv); + addKeysColumnHeader(originData, multiCsv); + angular.forEach(originData, function(oldRow, index) { + var row = angular.copy(originData[index]); + var dataString, infoArray; - dataString = infoArray.join(options.fieldSep ? options.fieldSep : ","); - csvContent += index < arrData.length ? dataString + EOL : dataString; - }); + infoArray = []; - // Add BOM if needed - if (options.addByteOrderMarker) { - csv += BOM; - } + var iterator = !!options.columnOrder ? options.columnOrder : row; + angular.forEach(iterator, function(field, key) { + var val = !!options.columnOrder ? row[field] : field; + this.push(that.stringifyField(val, options)); + }, infoArray); + + dataString = infoArray.join(options.fieldSep ? options.fieldSep : ","); + csvContent += index < originData.length ? dataString + EOL : dataString; + }); + } + + function addHeader(key, multiCsv) { + // Check if there's a provided header array + if (angular.isDefined(options.header) && options.header) { + var encodingArray, headerString; + + encodingArray = []; + if (multiCsv) { + angular.forEach(options.header[key], function(title, key) { + this.push(that.stringifyField(title, options)); + }, encodingArray); + } else { + angular.forEach(options.header, function(title, key) { + this.push(that.stringifyField(title, options)); + }, encodingArray); + } + + headerString = encodingArray.join(options.fieldSep ? options.fieldSep : ","); + csvContent += headerString + EOL; + } + } - // Append the content and resolve. - csv += csvContent; - def.resolve(csv); - }); + // Add BOM if needed + if (options.addByteOrderMarker) { + csv += BOM; + } - if (typeof dataPromise['catch'] === 'function') { - dataPromise['catch'](function (err) { - def.reject(err); + // Append the content and resolve. + csv += csvContent; + def.resolve(csv); }); - } - return def.promise; + if (typeof dataPromise['catch'] === 'function') { + dataPromise['catch'](function(err) { + def.reject(err); + }); + } + + return def.promise; }; /** @@ -182,8 +216,8 @@ angular.module('ngCsv.services'). * @param input * @returns {boolean} */ - this.isSpecialChar = function(input){ - return specialChars[input] !== undefined; + this.isSpecialChar = function(input) { + return specialChars[input] !== undefined; }; /** @@ -192,13 +226,15 @@ angular.module('ngCsv.services'). * @param input * @returns {special character string} */ - this.getSpecialChar = function (input) { - return specialChars[input]; + this.getSpecialChar = function(input) { + return specialChars[input]; }; + this.capitalize = function(input) { + return input.charAt(0).toUpperCase() + input.slice(1); + }; - }]); -/** +}]);/** * ng-csv module * Export Javascript's arrays to csv files from the browser * @@ -221,7 +257,8 @@ angular.module('ngCsv.directives'). addByteOrderMarker: "@addBom", ngClick: '&', charset: '@charset', - label: '&csvLabel' + label: '&csvLabel', + multiCsv: '&multiCsv' }, controller: [ '$scope', @@ -253,6 +290,7 @@ angular.module('ngCsv.directives'). if (angular.isDefined($attrs.csvHeader)) options.header = $scope.$eval($scope.header); if (angular.isDefined($attrs.csvColumnOrder)) options.columnOrder = $scope.$eval($scope.columnOrder); if (angular.isDefined($attrs.csvLabel)) options.label = $scope.$eval($scope.label); + if (angular.isDefined($attrs.multiCsv)) options.multiCsv = $scope.$eval($scope.multiCsv); options.fieldSep = $scope.fieldSep ? $scope.fieldSep : ","; diff --git a/build/ng-csv.min.js b/build/ng-csv.min.js index 94dcd7f..428e8e8 100644 --- a/build/ng-csv.min.js +++ b/build/ng-csv.min.js @@ -1,2 +1,2 @@ -/*! ng-csv 10-10-2015 */ -!function(a){angular.module("ngCsv.config",[]).value("ngCsv.config",{debug:!0}).config(["$compileProvider",function(a){angular.isDefined(a.urlSanitizationWhitelist)?a.urlSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|data):/):a.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|data):/)}]),angular.module("ngCsv.directives",["ngCsv.services"]),angular.module("ngCsv.services",[]),angular.module("ngCsv",["ngCsv.config","ngCsv.services","ngCsv.directives","ngSanitize"]),"undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="ngCsv"),angular.module("ngCsv.services").service("CSV",["$q",function(a){var b="\r\n",c="",d={"\\t":" ","\\b":"\b","\\v":" ","\\f":"\f","\\r":"\r"};this.stringifyField=function(a,b){return"locale"===b.decimalSep&&this.isFloat(a)?a.toLocaleString():"."!==b.decimalSep&&this.isFloat(a)?a.toString().replace(".",b.decimalSep):"string"==typeof a?(a=a.replace(/"/g,'""'),(b.quoteStrings||a.indexOf(",")>-1||a.indexOf("\n")>-1||a.indexOf("\r")>-1)&&(a=b.txtDelim+a+b.txtDelim),a):"boolean"==typeof a?a?"TRUE":"FALSE":a},this.isFloat=function(a){return+a===a&&(!isFinite(a)||Boolean(a%1))},this.stringify=function(d,e){var f=a.defer(),g=this,h="",i="",j=a.when(d).then(function(a){if(angular.isDefined(e.header)&&e.header){var d,j;d=[],angular.forEach(e.header,function(a){this.push(g.stringifyField(a,e))},d),j=d.join(e.fieldSep?e.fieldSep:","),i+=j+b}var k=[];if(angular.isArray(a)?k=a:angular.isFunction(a)&&(k=a()),angular.isDefined(e.label)&&e.label&&"boolean"==typeof e.label){var l,m;l=[],angular.forEach(k[0],function(a,b){this.push(g.stringifyField(b,e))},l),m=l.join(e.fieldSep?e.fieldSep:","),i+=m+b}angular.forEach(k,function(a,c){var d,f,h=angular.copy(k[c]);f=[];var j=e.columnOrder?e.columnOrder:h;angular.forEach(j,function(a){var b=e.columnOrder?h[a]:a;this.push(g.stringifyField(b,e))},f),d=f.join(e.fieldSep?e.fieldSep:","),i+=c'),h=angular.element(g.children()[0]);h.attr("href",a.URL.createObjectURL(d)),h.attr("download",b.getFilename()),h.attr("target","_blank"),e.find("body").append(g),f(function(){h[0].click(),h.remove()},null)}}c.bind("click",function(){b.buildCSV().then(function(){d()}),b.$apply()})}}}])}(window,document); \ No newline at end of file +/*! ng-csv 20-08-2016 */ +!function(a,b){angular.module("ngCsv.config",[]).value("ngCsv.config",{debug:!0}).config(["$compileProvider",function(a){angular.isDefined(a.urlSanitizationWhitelist)?a.urlSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|data):/):a.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|data):/)}]),angular.module("ngCsv.directives",["ngCsv.services"]),angular.module("ngCsv.services",[]),angular.module("ngCsv",["ngCsv.config","ngCsv.services","ngCsv.directives","ngSanitize"]),"undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="ngCsv"),angular.module("ngCsv.services").service("CSV",["$q",function(a){var b="\r\n",c="\ufeff",d={"\\t":" ","\\b":"\b","\\v":" ","\\f":"\f","\\r":"\r"};this.stringifyField=function(a,b){return"locale"===b.decimalSep&&this.isFloat(a)?a.toLocaleString():"."!==b.decimalSep&&this.isFloat(a)?a.toString().replace(".",b.decimalSep):"string"==typeof a?(a=a.replace(/"/g,'""'),(b.quoteStrings||a.indexOf(",")>-1||a.indexOf("\n")>-1||a.indexOf("\r")>-1)&&(a=b.txtDelim+a+b.txtDelim),a):"boolean"==typeof a?a?"TRUE":"FALSE":a},this.isFloat=function(a){return+a===a&&(!isFinite(a)||Boolean(a%1))},this.stringify=function(d,e){var f=a.defer(),g=this,h="",i="",j=a.when(d).then(function(a){function d(a,c){if(angular.isDefined(e.label)&&e.label&&"boolean"==typeof e.label){var d,f,h;d=[],h=c?e.columnOrder?e.columnOrder:a[0]:e.columnOrder?e.columnOrder:l[0],angular.forEach(h,function(a,b){var c=e.columnOrder?a:b;this.push(g.stringifyField(c,e))},d),f=d.join(e.fieldSep?e.fieldSep:","),i+=f+b}}function j(a,c,f){k(f,c),d(a,c),angular.forEach(a,function(c,d){var f,h,j=angular.copy(a[d]);h=[];var k=e.columnOrder?e.columnOrder:j;angular.forEach(k,function(a,b){var c=e.columnOrder?j[a]:a;this.push(g.stringifyField(c,e))},h),f=h.join(e.fieldSep?e.fieldSep:","),i+=d'),h=angular.element(g.children()[0]);h.attr("href",a.URL.createObjectURL(d)),h.attr("download",b.getFilename()),h.attr("target","_blank"),e.find("body").append(g),f(function(){h[0].click(),h.remove()},null)}}c.bind("click",function(a){b.buildCSV().then(function(a){g()}),b.$apply()})}}}])}(window,document); \ No newline at end of file diff --git a/example/index.html b/example/index.html index d541a0c..14f788e 100644 --- a/example/index.html +++ b/example/index.html @@ -15,6 +15,24 @@

ngCsv example

+
+ +
+ $scope.getArray = {{ getArray }} +
+
+ +
+ +
+ $scope.getArray = {{ multiArray }} +
+
+
@@ -39,17 +57,25 @@

ngCsv example

>Export to CSV with header + + + +
@@ -60,6 +86,7 @@

ngCsv example

myapp.controller('myctrl', function ($scope) { $scope.filename = "test"; $scope.getArray = [{a: 1, b:2}, {a:3, b:4}]; + $scope.multiArray = {array1:[{a: 1, b:2}],array2:[{a:3, b:4}]}; $scope.addRandomRow = function() { $scope.getArray.push({a: Math.floor((Math.random()*10)+1), b: Math.floor((Math.random()*10)+1)}); @@ -67,6 +94,10 @@

ngCsv example

$scope.getHeader = function () {return ["A", "B"]}; + $scope.getMultiHeader = function () { + return {array1:["A", "B"],array2:["A", "B"]} + }; + $scope.clickFn = function() { console.log("click click click"); }; diff --git a/package.json b/package.json index 67bc4a3..0e5e015 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "karma": "^0.12.16", "karma-chrome-launcher": "^0.1.3", "karma-jasmine": "^0.2.2", - "karma-phantomjs-launcher": "^0.1.4", + "karma-phantomjs-launcher": "^1.0.0", "matchdep": "^0.1.2" }, "engines": { diff --git a/src/ng-csv/directives/ng-csv.js b/src/ng-csv/directives/ng-csv.js index bfb80f9..0b60528 100644 --- a/src/ng-csv/directives/ng-csv.js +++ b/src/ng-csv/directives/ng-csv.js @@ -21,7 +21,8 @@ angular.module('ngCsv.directives'). addByteOrderMarker: "@addBom", ngClick: '&', charset: '@charset', - label: '&csvLabel' + label: '&csvLabel', + multiCsv: '&multiCsv' }, controller: [ '$scope', @@ -53,6 +54,7 @@ angular.module('ngCsv.directives'). if (angular.isDefined($attrs.csvHeader)) options.header = $scope.$eval($scope.header); if (angular.isDefined($attrs.csvColumnOrder)) options.columnOrder = $scope.$eval($scope.columnOrder); if (angular.isDefined($attrs.csvLabel)) options.label = $scope.$eval($scope.label); + if (angular.isDefined($attrs.multiCsv)) options.multiCsv = $scope.$eval($scope.multiCsv); options.fieldSep = $scope.fieldSep ? $scope.fieldSep : ","; diff --git a/src/ng-csv/services/csv-service.js b/src/ng-csv/services/csv-service.js index 3adade6..c459cff 100644 --- a/src/ng-csv/services/csv-service.js +++ b/src/ng-csv/services/csv-service.js @@ -2,17 +2,17 @@ * Created by asafdav on 15/05/14. */ angular.module('ngCsv.services'). - service('CSV', ['$q', function ($q) { +service('CSV', ['$q', function($q) { var EOL = '\r\n'; var BOM = "\ufeff"; var specialChars = { - '\\t': '\t', - '\\b': '\b', - '\\v': '\v', - '\\f': '\f', - '\\r': '\r' + '\\t': '\t', + '\\b': '\b', + '\\v': '\v', + '\\f': '\f', + '\\r': '\r' }; /** @@ -21,30 +21,30 @@ angular.module('ngCsv.services'). * @param options * @returns {*} */ - this.stringifyField = function (data, options) { - if (options.decimalSep === 'locale' && this.isFloat(data)) { - return data.toLocaleString(); - } + this.stringifyField = function(data, options) { + if (options.decimalSep === 'locale' && this.isFloat(data)) { + return data.toLocaleString(); + } - if (options.decimalSep !== '.' && this.isFloat(data)) { - return data.toString().replace('.', options.decimalSep); - } + if (options.decimalSep !== '.' && this.isFloat(data)) { + return data.toString().replace('.', options.decimalSep); + } - if (typeof data === 'string') { - data = data.replace(/"/g, '""'); // Escape double qoutes + if (typeof data === 'string') { + data = data.replace(/"/g, '""'); // Escape double qoutes - if (options.quoteStrings || data.indexOf(',') > -1 || data.indexOf('\n') > -1 || data.indexOf('\r') > -1) { - data = options.txtDelim + data + options.txtDelim; - } + if (options.quoteStrings || data.indexOf(',') > -1 || data.indexOf('\n') > -1 || data.indexOf('\r') > -1) { + data = options.txtDelim + data + options.txtDelim; + } - return data; - } + return data; + } - if (typeof data === 'boolean') { - return data ? 'TRUE' : 'FALSE'; - } + if (typeof data === 'boolean') { + return data ? 'TRUE' : 'FALSE'; + } - return data; + return data; }; /** @@ -52,8 +52,8 @@ angular.module('ngCsv.services'). * @param input * @returns {boolean} */ - this.isFloat = function (input) { - return +input === input && (!isFinite(input) || Boolean(input % 1)); + this.isFloat = function(input) { + return +input === input && (!isFinite(input) || Boolean(input % 1)); }; /** @@ -65,85 +65,116 @@ angular.module('ngCsv.services'). * * addByteOrderMarker - Add Byte order mark, default(false) * @param callback */ - this.stringify = function (data, options) { - var def = $q.defer(); - - var that = this; - var csv = ""; - var csvContent = ""; - - var dataPromise = $q.when(data).then(function (responseData) { - //responseData = angular.copy(responseData);//moved to row creation - // Check if there's a provided header array - if (angular.isDefined(options.header) && options.header) { - var encodingArray, headerString; - - encodingArray = []; - angular.forEach(options.header, function (title, key) { - this.push(that.stringifyField(title, options)); - }, encodingArray); - - headerString = encodingArray.join(options.fieldSep ? options.fieldSep : ","); - csvContent += headerString + EOL; - } - - var arrData = []; - - if (angular.isArray(responseData)) { - arrData = responseData; - } - else if (angular.isFunction(responseData)) { - arrData = responseData(); - } - - // Check if using keys as labels - if (angular.isDefined(options.label) && options.label && typeof options.label === 'boolean') { - var labelArray, labelString; - - labelArray = []; - - var iterator = !!options.columnOrder ? options.columnOrder : arrData[0]; - angular.forEach(iterator, function(value, label) { - var val = !!options.columnOrder ? value : label; - this.push(that.stringifyField(val, options)); - }, labelArray); - labelString = labelArray.join(options.fieldSep ? options.fieldSep : ","); - csvContent += labelString + EOL; - } - - angular.forEach(arrData, function (oldRow, index) { - var row = angular.copy(arrData[index]); - var dataString, infoArray; - - infoArray = []; - - var iterator = !!options.columnOrder ? options.columnOrder : row; - angular.forEach(iterator, function (field, key) { - var val = !!options.columnOrder ? row[field] : field; - this.push(that.stringifyField(val, options)); - }, infoArray); - - dataString = infoArray.join(options.fieldSep ? options.fieldSep : ","); - csvContent += index < arrData.length ? dataString + EOL : dataString; + this.stringify = function(data, options) { + var def = $q.defer(); + + var that = this; + var csv = ""; + var csvContent = ""; + + var dataPromise = $q.when(data).then(function(responseData) { + + var arrData = []; + + if (angular.isArray(responseData)) { + arrData = responseData; + } else if (angular.isFunction(responseData)) { + arrData = responseData(); + } else if (angular.isObject(responseData)) { + arrData = responseData; + } + + // Check if needs to write multiple csv files + if (angular.isDefined(options.multiCsv) && options.multiCsv && typeof options.multiCsv === 'boolean') { + angular.forEach(arrData, function(val, key) { + csvContent += that.capitalize(key) + EOL; + JsonObjectToCSV(val, true,key); + csvContent += EOL; + }); + } else { + JsonObjectToCSV(arrData, false,""); + } + + function addKeysColumnHeader(originData, multiCsv) { + // Check if using keys as labels + if (angular.isDefined(options.label) && options.label && typeof options.label === 'boolean') { + var labelArray, labelString, iterator; + + labelArray = []; + + if (multiCsv) { + iterator = !!options.columnOrder ? options.columnOrder : originData[0]; + } else { + iterator = !!options.columnOrder ? options.columnOrder : arrData[0]; + } + + angular.forEach(iterator, function(value, label) { + var val = !!options.columnOrder ? value : label; + this.push(that.stringifyField(val, options)); + }, labelArray); + labelString = labelArray.join(options.fieldSep ? options.fieldSep : ","); + csvContent += labelString + EOL; + } + } + + function JsonObjectToCSV(originData, multiCsv,dataLabel) { + addHeader(dataLabel, multiCsv); + addKeysColumnHeader(originData, multiCsv); + angular.forEach(originData, function(oldRow, index) { + var row = angular.copy(originData[index]); + var dataString, infoArray; + + infoArray = []; + + var iterator = !!options.columnOrder ? options.columnOrder : row; + angular.forEach(iterator, function(field, key) { + var val = !!options.columnOrder ? row[field] : field; + this.push(that.stringifyField(val, options)); + }, infoArray); + + dataString = infoArray.join(options.fieldSep ? options.fieldSep : ","); + csvContent += index < originData.length ? dataString + EOL : dataString; + }); + } + + function addHeader(key, multiCsv) { + // Check if there's a provided header array + if (angular.isDefined(options.header) && options.header) { + var encodingArray, headerString; + + encodingArray = []; + if (multiCsv) { + angular.forEach(options.header[key], function(title, key) { + this.push(that.stringifyField(title, options)); + }, encodingArray); + } else { + angular.forEach(options.header, function(title, key) { + this.push(that.stringifyField(title, options)); + }, encodingArray); + } + + headerString = encodingArray.join(options.fieldSep ? options.fieldSep : ","); + csvContent += headerString + EOL; + } + } + + // Add BOM if needed + if (options.addByteOrderMarker) { + csv += BOM; + } + + // Append the content and resolve. + csv += csvContent; + def.resolve(csv); }); - // Add BOM if needed - if (options.addByteOrderMarker) { - csv += BOM; + if (typeof dataPromise['catch'] === 'function') { + dataPromise['catch'](function(err) { + def.reject(err); + }); } - // Append the content and resolve. - csv += csvContent; - def.resolve(csv); - }); - - if (typeof dataPromise['catch'] === 'function') { - dataPromise['catch'](function (err) { - def.reject(err); - }); - } - - return def.promise; + return def.promise; }; /** @@ -151,8 +182,8 @@ angular.module('ngCsv.services'). * @param input * @returns {boolean} */ - this.isSpecialChar = function(input){ - return specialChars[input] !== undefined; + this.isSpecialChar = function(input) { + return specialChars[input] !== undefined; }; /** @@ -161,9 +192,12 @@ angular.module('ngCsv.services'). * @param input * @returns {special character string} */ - this.getSpecialChar = function (input) { - return specialChars[input]; + this.getSpecialChar = function(input) { + return specialChars[input]; }; + this.capitalize = function(input) { + return input.charAt(0).toUpperCase() + input.slice(1); + }; - }]); +}]); \ No newline at end of file diff --git a/test/unit/ngCsv/directives/ngCsv.js b/test/unit/ngCsv/directives/ngCsv.js index f5c6332..ad87dba 100644 --- a/test/unit/ngCsv/directives/ngCsv.js +++ b/test/unit/ngCsv/directives/ngCsv.js @@ -532,4 +532,69 @@ describe('ngCsv directive', function () { scope.$apply(); }); + + it('Creates multiple contents in one csv file if multi-csv sets to true', function (done) { + // Compile a piece of HTML containing the directive + $rootScope.testDelim = { array1: [{a:1, b:2, c:3}, {a:4, b:5, c:6}], array2: [{x:1, y:2, z:3, m:4}, {x:5, y:6, z:7, m:8}] }; + var element = $compile( + '
')($rootScope); + + $rootScope.$digest(); + + var scope = element.isolateScope(); + + // Check that the compiled element contains the templated content + expect(scope.$eval(scope.data)).toEqual($rootScope.testDelim); + + + scope.buildCSV(scope.data).then(function() { + expect(scope.csv).toBe('Array1\r\n1,2,3\r\n4,5,6\r\n\r\nArray2\r\n1,2,3,4\r\n5,6,7,8\r\n\r\n'); + done(); + }); + scope.$apply(); + }); + + it('should create csv content multi-csv & csv-label is true', function (done) { + // Compile a piece of HTML containing the directive + $rootScope.testDelim = { array1: [{a:1, b:2, c:3}, {a:4, b:5, c:6}], array2: [{x:1, y:2, z:3, m:4}, {x:5, y:6, z:7, m:8}] }; + var element = $compile( + '
')($rootScope); + + $rootScope.$digest(); + + var scope = element.isolateScope(); + + // Check that the compiled element contains the templated content + expect(scope.$eval(scope.data)).toEqual($rootScope.testDelim); + + + scope.buildCSV(scope.data).then(function() { + expect(scope.csv).toBe('Array1\r\na,b,c\r\n1,2,3\r\n4,5,6\r\n\r\nArray2\r\nx,y,z,m\r\n1,2,3,4\r\n5,6,7,8\r\n\r\n'); + done(); + }); + scope.$apply(); + }); + + it('should create csv content multi-csv is true & csv-headers are provided', function (done) { + // Compile a piece of HTML containing the directive + $rootScope.testDelim = { array1: [{a:1, b:2, c:3}, {a:4, b:5, c:6}], array2: [{x:1, y:2, z:3, m:4}, {x:5, y:6, z:7, m:8}] }; + $rootScope.testHeaders = { array1: ["A","B","C"], array2: ["X","Y","Z","M"] }; + var element = $compile( + '
')($rootScope); + + $rootScope.$digest(); + + var scope = element.isolateScope(); + + // Check that the compiled element contains the templated content + expect(scope.$eval(scope.data)).toEqual($rootScope.testDelim); + + + scope.buildCSV(scope.data).then(function() { + expect(scope.csv).toBe('Array1\r\nA,B,C\r\n1,2,3\r\n4,5,6\r\n\r\nArray2\r\nX,Y,Z,M\r\n1,2,3,4\r\n5,6,7,8\r\n\r\n'); + done(); + }); + scope.$apply(); + }); + });