Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-Csv Feature with example #180

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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/
Expand Down
230 changes: 134 additions & 96 deletions build/ng-csv.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
};

/**
Expand All @@ -55,39 +55,39 @@ 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;
};

/**
* Helper function to check if input is float
* @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));
};

/**
Expand All @@ -99,91 +99,125 @@ 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;
};

/**
* Helper function to check if input is really a special character
* @param input
* @returns {boolean}
*/
this.isSpecialChar = function(input){
return specialChars[input] !== undefined;
this.isSpecialChar = function(input) {
return specialChars[input] !== undefined;
};

/**
Expand All @@ -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
*
Expand All @@ -221,7 +257,8 @@ angular.module('ngCsv.directives').
addByteOrderMarker: "@addBom",
ngClick: '&',
charset: '@charset',
label: '&csvLabel'
label: '&csvLabel',
multiCsv: '&multiCsv'
},
controller: [
'$scope',
Expand Down Expand Up @@ -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 : ",";

Expand Down
Loading