I\'ve followed this post How to export JavaScript array info to csv (on client side)? to get a nested js array written as a csv file.
The array looks like:
I created this code for creating a nice, readable csv files:
var objectToCSVRow = function(dataObject) {
var dataArray = new Array;
for (var o in dataObject) {
var innerValue = dataObject[o]===null?'':dataObject[o].toString();
var result = innerValue.replace(/"/g, '""');
result = '"' + result + '"';
dataArray.push(result);
}
return dataArray.join(' ') + '\r\n';
}
var exportToCSV = function(arrayOfObjects) {
if (!arrayOfObjects.length) {
return;
}
var csvContent = "data:text/csv;charset=utf-8,";
// headers
csvContent += objectToCSVRow(Object.keys(arrayOfObjects[0]));
arrayOfObjects.forEach(function(item){
csvContent += objectToCSVRow(item);
});
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "customers.csv");
document.body.appendChild(link); // Required for FF
link.click();
document.body.removeChild(link);
}
In your case, since you use arrays in array instead of objects in array, You will skip the header part, but you could add the column names yourself by putting this instead of that part:
// headers
csvContent += '"Column name 1" "Column name 2" "Column name 3"\n';
The secret is that a space separates the columns in the csv file, and we put the column values in the double quotes to allow spaces, and escape any double quotes in the values themselves.
Also note that I replace null values with empty string, because that suited my needs, but you can change that and replace it with anything you like.
If your data contains any newlines or commas, you will need to escape those first:
const escape = text =>
text.replace(/\\/g, "\\\\")
.replace(/\n/g, "\\n")
.replace(/,/g, "\\,")
escaped_array = test_array.map(fields => fields.map(escape))
Then simply do:
csv = escaped_array.map(fields => fields.join(","))
.join("\n")
If you want to make it downloadable in-browser:
dl = "data:text/csv;charset=utf-8," + csv
window.open(encodeURI(dl))
The cited answer was wrong. You had to change
csvContent += index < infoArray.length ? dataString+ "\n" : dataString;
to
csvContent += dataString + "\n";
As to why the cited answer was wrong (funny it has been accepted!): index
, the second parameter of the forEach
callback function, is the index in the looped-upon array, and it makes no sense to compare this to the size of infoArray
, which is an item of said array (which happens to be an array too).
Six years have passed now since I wrote this answer. Many things have changed, including browsers. The following was part of the answer:
START of aged part
BTW, the cited code is suboptimal. You should avoid to repeatedly append to a string. You should append to an array instead, and do an array.join("\n") at the end. Like this:
var lineArray = [];
data.forEach(function (infoArray, index) {
var line = infoArray.join(",");
lineArray.push(index == 0 ? "data:text/csv;charset=utf-8," + line : line);
});
var csvContent = lineArray.join("\n");
END of aged part
(Keep in mind that the CSV case is a bit different from generic string concatenation, since for every string you also have to add the separator.)
Anyway, the above seems not to be true anymore, at least not for Chrome and Firefox (it seems to still be true for Safari, though).
To put an end to uncertainty, I wrote a jsPerf test that tests whether, in order to concatenate strings in a comma-separated way, it's faster to push them onto an array and join the array, or to concatenate them first with the comma, and then directly with the result string using the += operator.
Please follow the link and run the test, so that we have enough data to be able to talk about facts instead of opinions.