Javascript export csv file name - javascript

I have html table (table id='testTable') and a button in html:
<button id="btnExport" onclick="javascript:xport.toCSV('testTable');">CSV</button>
and javascript code:
toCSV: function(tableId, filename) {
var date=new Date();
this._filename = (typeof filename === 'undefined') ? tableId : filename;
// Generate our CSV string from out HTML Table
var csv = this._tableToCSV(document.getElementById(tableId));
// Create a CSV Blob
var blob = new Blob([csv], { type: "text/csv" });
// Determine which approach to take for the download
if (navigator.msSaveOrOpenBlob) {
// Works for Internet Explorer and Microsoft Edge
navigator.msSaveOrOpenBlob(blob, this._filename + ".csv");
} else {
this._downloadAnchor(URL.createObjectURL(blob), 'csv');
}
}
_tableToCSV: function(table) {
// We'll be co-opting `slice` to create arrays
var slice = Array.prototype.slice;
return slice
.call(table.rows)
.map(function(row) {
return slice
.call(row.cells)
.map(function(cell) {
return '"t"'.replace("t", cell.textContent);
})
.join(",");
})
.join("\r\n");
}
i want to change the filename to current date how can I do that?

first change toCSV to:
toCSV: function(tableId, filename) {
var date = new Date();
this._filename = (typeof filename === 'undefined') ? date : filename;
// Generate our CSV string from out HTML Table
var csv = this._tableToCSV(document.getElementById(tableId));
// Create a CSV Blob
var blob = new Blob([csv], { type: "text/csv" });
// Determine which approach to take for the download
if (navigator.msSaveOrOpenBlob) {
// Works for Internet Explorer and Microsoft Edge
navigator.msSaveOrOpenBlob(blob, this._filename + ".csv");
} else {
this._downloadAnchor(URL.createObjectURL(blob), 'csv',this._filename);
}
}
second change _downloadAnchor to:
_downloadAnchor: function(content, ext, filename) {
var anchor = document.createElement("a");
anchor.style = "display:none !important";
anchor.id = "downloadanchor";
document.body.appendChild(anchor);
// If the [download] attribute is supported, try to use it
if ("download" in anchor) {
anchor.download = filename + "." + ext;
}
anchor.href = content;
anchor.click();
anchor.remove();
}

_downloadAnchor: function(content, ext) {
var anchor = document.createElement("a");
anchor.style = "display:none !important";
anchor.id = "downloadanchor";
document.body.appendChild(anchor);
// If the [download] attribute is supported, try to use it
if ("download" in anchor) {
anchor.download = this._filename + "." + ext;
}
anchor.href = content;
anchor.click();
anchor.remove();
}

Related

Creating a CSV file where each column is an array of data [duplicate]

I know there are lot of questions of this nature but I need to do this using JavaScript. I am using Dojo 1.8 and have all the attribute info in array, which looks like this:
[["name1", "city_name1", ...]["name2", "city_name2", ...]]
Any idea how I can export this to CSV on the client side?
You can do this in native JavaScript. You'll have to parse your data into correct CSV format as so (assuming you are using an array of arrays for your data as you have described in the question):
const rows = [
["name1", "city1", "some other info"],
["name2", "city2", "more info"]
];
let csvContent = "data:text/csv;charset=utf-8,";
rows.forEach(function(rowArray) {
let row = rowArray.join(",");
csvContent += row + "\r\n";
});
or the shorter way (using arrow functions):
const rows = [
["name1", "city1", "some other info"],
["name2", "city2", "more info"]
];
let csvContent = "data:text/csv;charset=utf-8,"
+ rows.map(e => e.join(",")).join("\n");
Then you can use JavaScript's window.open and encodeURI functions to download the CSV file like so:
var encodedUri = encodeURI(csvContent);
window.open(encodedUri);
Edit: If you want to give your file a specific name, you have to do things a little differently since this is not supported accessing a data URI using the window.open method. In order to achieve this, you can create a hidden <a> DOM node and set its download attribute as follows:
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "my_data.csv");
document.body.appendChild(link); // Required for FF
link.click(); // This will download the data file named "my_data.csv".
Based on the answers above I created this function that I have tested on IE 11, Chrome 36 and Firefox 29
function exportToCsv(filename, rows) {
var processRow = function (row) {
var finalVal = '';
for (var j = 0; j < row.length; j++) {
var innerValue = row[j] === null ? '' : row[j].toString();
if (row[j] instanceof Date) {
innerValue = row[j].toLocaleString();
};
var result = innerValue.replace(/"/g, '""');
if (result.search(/("|,|\n)/g) >= 0)
result = '"' + result + '"';
if (j > 0)
finalVal += ',';
finalVal += result;
}
return finalVal + '\n';
};
var csvFile = '';
for (var i = 0; i < rows.length; i++) {
csvFile += processRow(rows[i]);
}
var blob = new Blob([csvFile], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, filename);
} else {
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}
For example:
https://jsfiddle.net/jossef/m3rrLzk0/
This solution should work with Internet Explorer 10+, Edge, old and new versions of Chrome, FireFox, Safari, ++
The accepted answer won't work with IE and Safari.
// Example data given in question text
var data = [
['name1', 'city1', 'some other info'],
['name2', 'city2', 'more info']
];
// Building the CSV from the Data two-dimensional array
// Each column is separated by ";" and new line "\n" for next row
var csvContent = '';
data.forEach(function(infoArray, index) {
dataString = infoArray.join(';');
csvContent += index < data.length ? dataString + '\n' : dataString;
});
// The download function takes a CSV string, the filename and mimeType as parameters
// Scroll/look down at the bottom of this snippet to see how download is called
var download = function(content, fileName, mimeType) {
var a = document.createElement('a');
mimeType = mimeType || 'application/octet-stream';
if (navigator.msSaveBlob) { // IE10
navigator.msSaveBlob(new Blob([content], {
type: mimeType
}), fileName);
} else if (URL && 'download' in a) { //html5 A[download]
a.href = URL.createObjectURL(new Blob([content], {
type: mimeType
}));
a.setAttribute('download', fileName);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} else {
location.href = 'data:application/octet-stream,' + encodeURIComponent(content); // only this mime type is supported
}
}
download(csvContent, 'dowload.csv', 'text/csv;encoding:utf-8');
Running the code snippet will download the mock data as csv
Credits to dandavis https://stackoverflow.com/a/16377813/1350598
A minimalistic yet feature-complete solution :)
/** Convert a 2D array into a CSV string
*/
function arrayToCsv(data){
return data.map(row =>
row
.map(String) // convert every value to String
.map(v => v.replaceAll('"', '""')) // escape double colons
.map(v => `"${v}"`) // quote it
.join(',') // comma-separated
).join('\r\n'); // rows starting on new lines
}
Example:
let csv = arrayToCsv([
[1, '2', '"3"'],
[true, null, undefined],
]);
Result:
"1","2","""3"""
"true","null","undefined"
Now download it as a file:
/** Download contents as a file
* Source: https://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side
*/
function downloadBlob(content, filename, contentType) {
// Create a blob
var blob = new Blob([content], { type: contentType });
var url = URL.createObjectURL(blob);
// Create a link to download it
var pom = document.createElement('a');
pom.href = url;
pom.setAttribute('download', filename);
pom.click();
}
Download it:
downloadBlob(csv, 'export.csv', 'text/csv;charset=utf-8;')
In Chrome 35 update, download attribute behavior was changed.
https://code.google.com/p/chromium/issues/detail?id=373182
to work this in chrome, use this
var pom = document.createElement('a');
var csvContent=csv; //here we load our csv data
var blob = new Blob([csvContent],{type: 'text/csv;charset=utf-8;'});
var url = URL.createObjectURL(blob);
pom.href = url;
pom.setAttribute('download', 'foo.csv');
pom.click();
I came here looking for a bit more RFC 4180 compliance and I failed to find an implementation, so I made a (possibly inefficient) one for my own needs. I thought I would share it with everyone.
var content = [['1st title', '2nd title', '3rd title', 'another title'], ['a a a', 'bb\nb', 'cc,c', 'dd"d'], ['www', 'xxx', 'yyy', 'zzz']];
var finalVal = '';
for (var i = 0; i < content.length; i++) {
var value = content[i];
for (var j = 0; j < value.length; j++) {
var innerValue = value[j]===null?'':value[j].toString();
var result = innerValue.replace(/"/g, '""');
if (result.search(/("|,|\n)/g) >= 0)
result = '"' + result + '"';
if (j > 0)
finalVal += ',';
finalVal += result;
}
finalVal += '\n';
}
console.log(finalVal);
var download = document.getElementById('download');
download.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(finalVal));
download.setAttribute('download', 'test.csv');
Hopefully this will help someone out in the future. This combines both the encoding of the CSV along with the ability to download the file. In my example on jsfiddle. You can download the file (assuming HTML 5 browser) or view the output in the console.
UPDATE:
Chrome now appears to have lost the ability to name the file. I'm not sure what's happened or how to fix it, but whenever I use this code (including the jsfiddle), the downloaded file is now named download.csv.
People are trying to create their own csv string, which fail on edge cases, e.g. special characters, surely this is a solved problem right?
papaparse - use for JSON to CSV encoding. Papa.unparse().
import Papa from "papaparse";
const downloadCSV = (args) => {
let filename = args.filename || 'export.csv';
let columns = args.columns || null;
let csv = Papa.unparse({ data: args.data, fields: columns})
if (csv == null) return;
var blob = new Blob([csv]);
if (window.navigator.msSaveOrOpenBlob) // IE hack; see http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx
window.navigator.msSaveBlob(blob, args.filename);
else
{
var a = window.document.createElement("a");
a.href = window.URL.createObjectURL(blob, {type: "text/plain"});
a.download = filename;
document.body.appendChild(a);
a.click(); // IE: "Access is denied"; see: https://connect.microsoft.com/IE/feedback/details/797361/ie-10-treats-blob-url-as-cross-origin-and-denies-access
document.body.removeChild(a);
}
}
Example usage
downloadCSV({
filename: "filename.csv",
data: [{"a": "1", "b": "2"}],
columns: ["a","b"]
});
https://github.com/mholt/PapaParse/issues/175 - See this comment for browser support discussion.
The solution from #Default works perfect on Chrome (thanks a lot for that!) but I had a problem with IE.
Here's a solution (works on IE10):
var csvContent=data; //here we load our csv data
var blob = new Blob([csvContent],{
type: "text/csv;charset=utf-8;"
});
navigator.msSaveBlob(blob, "filename.csv")
Working for all languages
function convertToCsv(fName, rows) {
var csv = '';
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
for (var j = 0; j < row.length; j++) {
var val = row[j] === null ? '' : row[j].toString();
val = val.replace(/\t/gi, " ");
if (j > 0)
csv += '\t';
csv += val;
}
csv += '\n';
}
// for UTF-16
var cCode, bArr = [];
bArr.push(255, 254);
for (var i = 0; i < csv.length; ++i) {
cCode = csv.charCodeAt(i);
bArr.push(cCode & 0xff);
bArr.push(cCode / 256 >>> 0);
}
var blob = new Blob([new Uint8Array(bArr)], { type: 'text/csv;charset=UTF-16LE;' });
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, fName);
} else {
var link = document.createElement("a");
if (link.download !== undefined) {
var url = window.URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", fName);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
}
}
}
convertToCsv('download.csv', [
['Order', 'Language'],
['1', 'English'],
['2', 'Español'],
['3', 'Français'],
['4', 'Português'],
['5', 'čeština'],
['6', 'Slovenščina'],
['7', 'Tiếng Việt'],
['8', 'Türkçe'],
['9', 'Norsk bokmål'],
['10', 'Ελληνικά'],
['11', 'беларускі'],
['12', 'русский'],
['13', 'Українська'],
['14', 'հայերեն'],
['15', 'עִברִית'],
['16', 'اردو'],
['17', 'नेपाली'],
['18', 'हिंदी'],
['19', 'ไทย'],
['20', 'ქართული'],
['21', '中国'],
['22', '한국어'],
['23', '日本語'],
])
You can use the below piece of code to export array to CSV file using Javascript.
This handles special characters part as well
var arrayContent = [["Séjour 1, é,í,ú,ü,ű"],["Séjour 2, é,í,ú,ü,ű"]];
var csvContent = arrayContent.join("\n");
var link = window.document.createElement("a");
link.setAttribute("href", "data:text/csv;charset=utf-8,%EF%BB%BF" + encodeURI(csvContent));
link.setAttribute("download", "upload_data.csv");
link.click();
Here is the link to working jsfiddle
Old question with many good answers, but here is another simple option that relies on two popular libraries to get it done. Some answers mention Papa Parse but roll their own solution for the download part. Combining Papa Parse and FileSaver.js, you can try the following:
const dataString = Papa.unparse(data, config);
const blob = new Blob([dataString], { type: 'text/csv;charset=utf-8' });
FileSaver.saveAs(blob, 'myfile.csv');
The config options for unparse are described here.
There you go :
<!doctype html>
<html>
<head></head>
<body>
<a href='#' onclick='downloadCSV({ filename: "stock-data.csv" });'>Download CSV</a>
<script type="text/javascript">
var stockData = [
{
Symbol: "AAPL",
Company: "Apple Inc.",
Price: "132.54"
},
{
Symbol: "INTC",
Company: "Intel Corporation",
Price: "33.45"
},
{
Symbol: "GOOG",
Company: "Google Inc",
Price: "554.52"
},
];
function convertArrayOfObjectsToCSV(args) {
var result, ctr, keys, columnDelimiter, lineDelimiter, data;
data = args.data || null;
if (data == null || !data.length) {
return null;
}
columnDelimiter = args.columnDelimiter || ',';
lineDelimiter = args.lineDelimiter || '\n';
keys = Object.keys(data[0]);
result = '';
result += keys.join(columnDelimiter);
result += lineDelimiter;
data.forEach(function(item) {
ctr = 0;
keys.forEach(function(key) {
if (ctr > 0) result += columnDelimiter;
result += item[key];
ctr++;
});
result += lineDelimiter;
});
return result;
}
window.downloadCSV = function(args) {
var data, filename, link;
var csv = convertArrayOfObjectsToCSV({
data: stockData
});
if (csv == null) return;
filename = args.filename || 'export.csv';
if (!csv.match(/^data:text\/csv/i)) {
csv = 'data:text/csv;charset=utf-8,' + csv;
}
data = encodeURI(csv);
link = document.createElement('a');
link.setAttribute('href', data);
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
</script>
</body>
</html>
//It work in Chrome and IE ... I reviewed and readed a lot of answer. then i used it and tested in both ...
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
var blob = new Blob([CSV], { type: 'text/csv;charset=utf-8;' });
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", fileName);
link.style = "visibility:hidden";
}
if (navigator.msSaveBlob) { // IE 10+
link.addEventListener("click", function (event) {
var blob = new Blob([CSV], {
"type": "text/csv;charset=utf-8;"
});
navigator.msSaveBlob(blob, fileName);
}, false);
}
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
//Regards
The following is a native js solution.
function export2csv() {
let data = "";
const tableData = [];
const rows = [
['111', '222', '333'],
['aaa', 'bbb', 'ccc'],
['AAA', 'BBB', 'CCC']
];
for (const row of rows) {
const rowData = [];
for (const column of row) {
rowData.push(column);
}
tableData.push(rowData.join(","));
}
data += tableData.join("\n");
const a = document.createElement("a");
a.href = URL.createObjectURL(new Blob([data], { type: "text/csv" }));
a.setAttribute("download", "data.csv");
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
<button onclick="export2csv()">Export array to csv file</button>
One arrow function with ES6 :
const dataToCsvURI = (data) => encodeURI(
`data:text/csv;charset=utf-8,${data.map((row, index) => row.join(',')).join(`\n`)}`
);
Then :
window.open(
dataToCsvURI(
[["name1", "city_name1"/*, ...*/], ["name2", "city_name2"/*, ...*/]]
)
);
In case anyone needs this for reactjs, react-csv is there for that
A lot of roll-your-own solutions here for converting data to CSV, but just about all of them will have various caveats in terms of the type of data they will correctly format without tripping up Excel or the likes.
Why not use something proven: Papa Parse
Papa.unparse(data[, config])
Then just combine this with one of the local download solutions here eg. the one by #ArneHB looks good.
There are two questions here:
How to convert an array to csv string
How to save that string to a file
All the answers to the first question (except the one by Milimetric) here seem like an overkill. And the one by Milimetric does not cover altrenative requirements, like surrounding strings with quotes or converting arrays of objects.
Here are my takes on this:
For a simple csv one map() and a join() are enough:
var test_array = [["name1", 2, 3], ["name2", 4, 5], ["name3", 6, 7], ["name4", 8, 9], ["name5", 10, 11]];
var csv = test_array.map(function(d){
return d.join();
}).join('\n');
/* Results in
name1,2,3
name2,4,5
name3,6,7
name4,8,9
name5,10,11
This method also allows you to specify column separator other than a comma in the inner join. for example a tab: d.join('\t')
On the other hand if you want to do it properly and enclose strings in quotes "", then you can use some JSON magic:
var csv = test_array.map(function(d){
return JSON.stringify(d);
})
.join('\n')
.replace(/(^\[)|(\]$)/mg, ''); // remove opening [ and closing ]
// brackets from each line
/* would produce
"name1",2,3
"name2",4,5
"name3",6,7
"name4",8,9
"name5",10,11
if you have array of objects like :
var data = [
{"title": "Book title 1", "author": "Name1 Surname1"},
{"title": "Book title 2", "author": "Name2 Surname2"},
{"title": "Book title 3", "author": "Name3 Surname3"},
{"title": "Book title 4", "author": "Name4 Surname4"}
];
// use
var csv = data.map(function(d){
return JSON.stringify(Object.values(d));
})
.join('\n')
.replace(/(^\[)|(\]$)/mg, '');
Create a blob with the csv data .ie var blob = new Blob([data], type:"text/csv");
If the browser supports saving of blobs i.e if window.navigator.mSaveOrOpenBlob)===true, then save the csv data using: window.navigator.msSaveBlob(blob, 'filename.csv')
If the browser doesn't support saving and opening of blobs, then save csv data as:
var downloadLink = document.createElement('<a></a>');
downloadLink.attr('href', window.URL.createObjectURL(blob));
downloadLink.attr('download', filename);
downloadLink.attr('target', '_blank');
document.body.append(downloadLink);
Full Code snippet:
var filename = 'data_'+(new Date()).getTime()+'.csv';
var charset = "utf-8";
var blob = new Blob([data], {
type: "text/csv;charset="+ charset + ";"
});
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, filename);
} else {
var downloadLink = document.element('<a></a>');
downloadLink.attr('href', window.URL.createObjectURL(blob));
downloadLink.attr('download', filename);
downloadLink.attr('target', '_blank');
document.body.append(downloadLink);
downloadLink[0].click();
}
From react-admin:
function downloadCsv(csv, filename) {
const fakeLink = document.createElement('a');
fakeLink.style.display = 'none';
document.body.appendChild(fakeLink);
const blob = new Blob([csv], { type: 'text/csv' });
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
// Manage IE11+ & Edge
window.navigator.msSaveOrOpenBlob(blob, `${filename}.csv`);
} else {
fakeLink.setAttribute('href', URL.createObjectURL(blob));
fakeLink.setAttribute('download', `${filename}.csv`);
fakeLink.click();
}
};
downloadCsv('Hello World', 'any-file-name.csv');
Here's how I download CSV files on the client side in my Java GWT application. Special thanks to Xavier John for his solution. It's been verified to work in FF 24.6.0, IE 11.0.20, and Chrome 45.0.2454.99 (64-bit). I hope this saves someone a bit of time:
public class ExportFile
{
private static final String CRLF = "\r\n";
public static void exportAsCsv(String filename, List<List<String>> data)
{
StringBuilder sb = new StringBuilder();
for(List<String> row : data)
{
for(int i=0; i<row.size(); i++)
{
if(i>0) sb.append(",");
sb.append(row.get(i));
}
sb.append(CRLF);
}
generateCsv(filename, sb.toString());
}
private static native void generateCsv(String filename, String text)
/*-{
var blob = new Blob([text], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) // IE 10+
{
navigator.msSaveBlob(blob, filename);
}
else
{
var link = document.createElement("a");
if (link.download !== undefined) // feature detection
{
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}-*/;
}
Simply try this, some of the answers here are not handling unicode data and data that has comma for example date.
function downloadUnicodeCSV(filename, datasource) {
var content = '', newLine = '\r\n';
for (var _i = 0, datasource_1 = datasource; _i < datasource_1.length; _i++) {
var line = datasource_1[_i];
var i = 0;
for (var _a = 0, line_1 = line; _a < line_1.length; _a++) {
var item = line_1[_a];
var it = item.replace(/"/g, '""');
if (it.search(/("|,|\n)/g) >= 0) {
it = '"' + it + '"';
}
content += (i > 0 ? ',' : '') + it;
++i;
}
content += newLine;
}
var link = document.createElement('a');
link.setAttribute('href', 'data:text/csv;charset=utf-8,%EF%BB%BF' + encodeURIComponent(content));
link.setAttribute('download', filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
Here's an Angular friendly version:
constructor(private location: Location, private renderer: Renderer2) {}
download(content, fileName, mimeType) {
const a = this.renderer.createElement('a');
mimeType = mimeType || 'application/octet-stream';
if (navigator.msSaveBlob) {
navigator.msSaveBlob(new Blob([content], {
type: mimeType
}), fileName);
}
else if (URL && 'download' in a) {
const id = GetUniqueID();
this.renderer.setAttribute(a, 'id', id);
this.renderer.setAttribute(a, 'href', URL.createObjectURL(new Blob([content], {
type: mimeType
})));
this.renderer.setAttribute(a, 'download', fileName);
this.renderer.appendChild(document.body, a);
const anchor = this.renderer.selectRootElement(`#${id}`);
anchor.click();
this.renderer.removeChild(document.body, a);
}
else {
this.location.go(`data:application/octet-stream,${encodeURIComponent(content)}`);
}
};
The answers above work, but keep in mind that if you are opening up in the .xls format, columns ~~might~~ be separated by '\t' instead of ',', the answer https://stackoverflow.com/a/14966131/6169225 worked well for me, so long as I used .join('\t') on the arrays instead of .join(',').
I use this function to convert an string[][] to a csv file. It quotes a cell, if it contains a ", a , or other whitespace (except blanks):
/**
* Takes an array of arrays and returns a `,` sparated csv file.
* #param {string[][]} table
* #returns {string}
*/
function toCSV(table) {
return table
.map(function(row) {
return row
.map(function(cell) {
// We remove blanks and check if the column contains
// other whitespace,`,` or `"`.
// In that case, we need to quote the column.
if (cell.replace(/ /g, '').match(/[\s,"]/)) {
return '"' + cell.replace(/"/g, '""') + '"';
}
return cell;
})
.join(',');
})
.join('\n'); // or '\r\n' for windows
}
Note: does not work on Internet Explorer < 11 unless map is polyfilled.
Note: If the cells contain numbers, you can add cell=''+cell before if (cell.replace... to convert numbers to strings.
Or you can write it in one line using ES6:
t.map(r=>r.map(c=>c.replace(/ /g, '').match(/[\s,"]/)?'"'+c.replace(/"/g,'""')+'"':c).join(',')).join('\n')
Download CSV File
let csvContent = "data:text/csv;charset=utf-8,";
rows.forEach(function (rowArray) {
for (var i = 0, len = rowArray.length; i < len; i++) {
if (typeof (rowArray[i]) == 'string')
rowArray[i] = rowArray[i].replace(/<(?:.|\n)*?>/gm, '');
rowArray[i] = rowArray[i].replace(/,/g, '');
}
let row = rowArray.join(",");
csvContent += row + "\r\n"; // add carriage return
});
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "fileName.csv");
document.body.appendChild(link);
link.click();
If you are looking for a really quick solution you can also give a chance to this small library which will create and download CSV file for you: https://github.com/mbrn/filefy
Usage is very simple:
import { CsvBuilder } from 'filefy';
var csvBuilder = new CsvBuilder("user_list.csv")
.setColumns(["name", "surname"])
.addRow(["Eve", "Holt"])
.addRows([
["Charles", "Morris"],
["Tracey", "Ramos"]
])
.exportFile();
In case anyone needs this for knockout js, it works ok with basically the proposed solution:
html:
<a data-bind="attr: {download: filename, href: csvContent}">Download</a>
view model:
// for the download link
this.filename = ko.computed(function () {
return ko.unwrap(this.id) + '.csv';
}, this);
this.csvContent = ko.computed(function () {
if (!this.csvLink) {
var data = ko.unwrap(this.data),
ret = 'data:text/csv;charset=utf-8,';
ret += data.map(function (row) {
return row.join(',');
}).join('\n');
return encodeURI(ret);
}
}, this);
I added to Xavier Johns function to also include the field headers if needed, uses jQuery though. The $.each bit will need changing for a native javascript loop
function exportToCsv(filename, rows, headers = false) {
var processRow = function (row) {
row = $.map(row, function(value, index) {
return [value];
});
var finalVal = '';
for (var j = 0; j < row.length; j++) {
if(i == 0 && j == 0 && headers == true){
var ii = 0;
$.each(rows[i], function( index, value ) {
//console.log(index);
var fieldName = index === null ? '' : index.toString();
//console.log(fieldName);
var fieldResult = fieldName.replace(/"/g, '""');
//console.log(fieldResult);
if (fieldResult.search(/("|,|\n)/g) >= 0){
fieldResult = '"' + fieldResult + '"';
}
//console.log(fieldResult);
if (ii > 0){
finalVal += ',';
finalVal += fieldResult;
}else{
finalVal += fieldResult;
}
ii++;
//console.log(finalVal);
});
finalVal += '\n';
//console.log('end: '+finalVal);
}
var innerValue = row[j] === null ? '' : row[j].toString();
if (row[j] instanceof Date) {
innerValue = row[j].toLocaleString();
};
var result = innerValue.replace(/"/g, '""');
if (result.search(/("|,|\n)/g) >= 0){
result = '"' + result + '"';
}
if (j > 0){
finalVal += ',';
finalVal += result;
}else{
finalVal += result;
}
}
return finalVal + '\n';
};
var csvFile = '';
for (var i = 0; i < rows.length; i++) {
csvFile += processRow(rows[i]);
}
var blob = new Blob([csvFile], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, filename);
}else{
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}
This is a modified answer based on the accepted answer wherein the data would be coming from JSON.
JSON Data Ouptut:
0 :{emails: "SAMPLE Co., peter#samplecompany.com"}, 1:{emails: "Another CO. , ronald#another.com"}
JS:
$.getJSON('yourlink_goes_here', { if_you_have_parameters}, function(data) {
var csvContent = "data:text/csv;charset=utf-8,";
var dataString = '';
$.each(data, function(k, v) {
dataString += v.emails + "\n";
});
csvContent += dataString;
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "your_filename.csv");
document.body.appendChild(link); // Required for FF
link.click();
});
This library helps a lot: https://www.npmjs.com/package/json-to-csv-in-browser
It automatically convert an array of jsons to an csv file and it even gives you the download functionality in case you want to prompt the web user to download the csv file.
It works like a charm with very little code.
import { JsonArray, download } from 'json-to-csv-in-browser'
const arr = [
{name : ` vader`, age : 53},
{name : "what", age : 38},
{name : "ever", age : 22}
]
const jsonArray = new JsonArray(arr);
const str = jsonArray.convertToCSVstring();
download("my.csv", str);
Cheers!
EDIT: testing it a little bit more, it doesn't work that well if your values have comma on them

Store data from javascript array as csv on local computer [duplicate]

I know there are lot of questions of this nature but I need to do this using JavaScript. I am using Dojo 1.8 and have all the attribute info in array, which looks like this:
[["name1", "city_name1", ...]["name2", "city_name2", ...]]
Any idea how I can export this to CSV on the client side?
You can do this in native JavaScript. You'll have to parse your data into correct CSV format as so (assuming you are using an array of arrays for your data as you have described in the question):
const rows = [
["name1", "city1", "some other info"],
["name2", "city2", "more info"]
];
let csvContent = "data:text/csv;charset=utf-8,";
rows.forEach(function(rowArray) {
let row = rowArray.join(",");
csvContent += row + "\r\n";
});
or the shorter way (using arrow functions):
const rows = [
["name1", "city1", "some other info"],
["name2", "city2", "more info"]
];
let csvContent = "data:text/csv;charset=utf-8,"
+ rows.map(e => e.join(",")).join("\n");
Then you can use JavaScript's window.open and encodeURI functions to download the CSV file like so:
var encodedUri = encodeURI(csvContent);
window.open(encodedUri);
Edit: If you want to give your file a specific name, you have to do things a little differently since this is not supported accessing a data URI using the window.open method. In order to achieve this, you can create a hidden <a> DOM node and set its download attribute as follows:
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "my_data.csv");
document.body.appendChild(link); // Required for FF
link.click(); // This will download the data file named "my_data.csv".
Based on the answers above I created this function that I have tested on IE 11, Chrome 36 and Firefox 29
function exportToCsv(filename, rows) {
var processRow = function (row) {
var finalVal = '';
for (var j = 0; j < row.length; j++) {
var innerValue = row[j] === null ? '' : row[j].toString();
if (row[j] instanceof Date) {
innerValue = row[j].toLocaleString();
};
var result = innerValue.replace(/"/g, '""');
if (result.search(/("|,|\n)/g) >= 0)
result = '"' + result + '"';
if (j > 0)
finalVal += ',';
finalVal += result;
}
return finalVal + '\n';
};
var csvFile = '';
for (var i = 0; i < rows.length; i++) {
csvFile += processRow(rows[i]);
}
var blob = new Blob([csvFile], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, filename);
} else {
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}
For example:
https://jsfiddle.net/jossef/m3rrLzk0/
This solution should work with Internet Explorer 10+, Edge, old and new versions of Chrome, FireFox, Safari, ++
The accepted answer won't work with IE and Safari.
// Example data given in question text
var data = [
['name1', 'city1', 'some other info'],
['name2', 'city2', 'more info']
];
// Building the CSV from the Data two-dimensional array
// Each column is separated by ";" and new line "\n" for next row
var csvContent = '';
data.forEach(function(infoArray, index) {
dataString = infoArray.join(';');
csvContent += index < data.length ? dataString + '\n' : dataString;
});
// The download function takes a CSV string, the filename and mimeType as parameters
// Scroll/look down at the bottom of this snippet to see how download is called
var download = function(content, fileName, mimeType) {
var a = document.createElement('a');
mimeType = mimeType || 'application/octet-stream';
if (navigator.msSaveBlob) { // IE10
navigator.msSaveBlob(new Blob([content], {
type: mimeType
}), fileName);
} else if (URL && 'download' in a) { //html5 A[download]
a.href = URL.createObjectURL(new Blob([content], {
type: mimeType
}));
a.setAttribute('download', fileName);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} else {
location.href = 'data:application/octet-stream,' + encodeURIComponent(content); // only this mime type is supported
}
}
download(csvContent, 'dowload.csv', 'text/csv;encoding:utf-8');
Running the code snippet will download the mock data as csv
Credits to dandavis https://stackoverflow.com/a/16377813/1350598
A minimalistic yet feature-complete solution :)
/** Convert a 2D array into a CSV string
*/
function arrayToCsv(data){
return data.map(row =>
row
.map(String) // convert every value to String
.map(v => v.replaceAll('"', '""')) // escape double colons
.map(v => `"${v}"`) // quote it
.join(',') // comma-separated
).join('\r\n'); // rows starting on new lines
}
Example:
let csv = arrayToCsv([
[1, '2', '"3"'],
[true, null, undefined],
]);
Result:
"1","2","""3"""
"true","null","undefined"
Now download it as a file:
/** Download contents as a file
* Source: https://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side
*/
function downloadBlob(content, filename, contentType) {
// Create a blob
var blob = new Blob([content], { type: contentType });
var url = URL.createObjectURL(blob);
// Create a link to download it
var pom = document.createElement('a');
pom.href = url;
pom.setAttribute('download', filename);
pom.click();
}
Download it:
downloadBlob(csv, 'export.csv', 'text/csv;charset=utf-8;')
In Chrome 35 update, download attribute behavior was changed.
https://code.google.com/p/chromium/issues/detail?id=373182
to work this in chrome, use this
var pom = document.createElement('a');
var csvContent=csv; //here we load our csv data
var blob = new Blob([csvContent],{type: 'text/csv;charset=utf-8;'});
var url = URL.createObjectURL(blob);
pom.href = url;
pom.setAttribute('download', 'foo.csv');
pom.click();
I came here looking for a bit more RFC 4180 compliance and I failed to find an implementation, so I made a (possibly inefficient) one for my own needs. I thought I would share it with everyone.
var content = [['1st title', '2nd title', '3rd title', 'another title'], ['a a a', 'bb\nb', 'cc,c', 'dd"d'], ['www', 'xxx', 'yyy', 'zzz']];
var finalVal = '';
for (var i = 0; i < content.length; i++) {
var value = content[i];
for (var j = 0; j < value.length; j++) {
var innerValue = value[j]===null?'':value[j].toString();
var result = innerValue.replace(/"/g, '""');
if (result.search(/("|,|\n)/g) >= 0)
result = '"' + result + '"';
if (j > 0)
finalVal += ',';
finalVal += result;
}
finalVal += '\n';
}
console.log(finalVal);
var download = document.getElementById('download');
download.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(finalVal));
download.setAttribute('download', 'test.csv');
Hopefully this will help someone out in the future. This combines both the encoding of the CSV along with the ability to download the file. In my example on jsfiddle. You can download the file (assuming HTML 5 browser) or view the output in the console.
UPDATE:
Chrome now appears to have lost the ability to name the file. I'm not sure what's happened or how to fix it, but whenever I use this code (including the jsfiddle), the downloaded file is now named download.csv.
People are trying to create their own csv string, which fail on edge cases, e.g. special characters, surely this is a solved problem right?
papaparse - use for JSON to CSV encoding. Papa.unparse().
import Papa from "papaparse";
const downloadCSV = (args) => {
let filename = args.filename || 'export.csv';
let columns = args.columns || null;
let csv = Papa.unparse({ data: args.data, fields: columns})
if (csv == null) return;
var blob = new Blob([csv]);
if (window.navigator.msSaveOrOpenBlob) // IE hack; see http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx
window.navigator.msSaveBlob(blob, args.filename);
else
{
var a = window.document.createElement("a");
a.href = window.URL.createObjectURL(blob, {type: "text/plain"});
a.download = filename;
document.body.appendChild(a);
a.click(); // IE: "Access is denied"; see: https://connect.microsoft.com/IE/feedback/details/797361/ie-10-treats-blob-url-as-cross-origin-and-denies-access
document.body.removeChild(a);
}
}
Example usage
downloadCSV({
filename: "filename.csv",
data: [{"a": "1", "b": "2"}],
columns: ["a","b"]
});
https://github.com/mholt/PapaParse/issues/175 - See this comment for browser support discussion.
The solution from #Default works perfect on Chrome (thanks a lot for that!) but I had a problem with IE.
Here's a solution (works on IE10):
var csvContent=data; //here we load our csv data
var blob = new Blob([csvContent],{
type: "text/csv;charset=utf-8;"
});
navigator.msSaveBlob(blob, "filename.csv")
Working for all languages
function convertToCsv(fName, rows) {
var csv = '';
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
for (var j = 0; j < row.length; j++) {
var val = row[j] === null ? '' : row[j].toString();
val = val.replace(/\t/gi, " ");
if (j > 0)
csv += '\t';
csv += val;
}
csv += '\n';
}
// for UTF-16
var cCode, bArr = [];
bArr.push(255, 254);
for (var i = 0; i < csv.length; ++i) {
cCode = csv.charCodeAt(i);
bArr.push(cCode & 0xff);
bArr.push(cCode / 256 >>> 0);
}
var blob = new Blob([new Uint8Array(bArr)], { type: 'text/csv;charset=UTF-16LE;' });
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, fName);
} else {
var link = document.createElement("a");
if (link.download !== undefined) {
var url = window.URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", fName);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
}
}
}
convertToCsv('download.csv', [
['Order', 'Language'],
['1', 'English'],
['2', 'Español'],
['3', 'Français'],
['4', 'Português'],
['5', 'čeština'],
['6', 'Slovenščina'],
['7', 'Tiếng Việt'],
['8', 'Türkçe'],
['9', 'Norsk bokmål'],
['10', 'Ελληνικά'],
['11', 'беларускі'],
['12', 'русский'],
['13', 'Українська'],
['14', 'հայերեն'],
['15', 'עִברִית'],
['16', 'اردو'],
['17', 'नेपाली'],
['18', 'हिंदी'],
['19', 'ไทย'],
['20', 'ქართული'],
['21', '中国'],
['22', '한국어'],
['23', '日本語'],
])
You can use the below piece of code to export array to CSV file using Javascript.
This handles special characters part as well
var arrayContent = [["Séjour 1, é,í,ú,ü,ű"],["Séjour 2, é,í,ú,ü,ű"]];
var csvContent = arrayContent.join("\n");
var link = window.document.createElement("a");
link.setAttribute("href", "data:text/csv;charset=utf-8,%EF%BB%BF" + encodeURI(csvContent));
link.setAttribute("download", "upload_data.csv");
link.click();
Here is the link to working jsfiddle
Old question with many good answers, but here is another simple option that relies on two popular libraries to get it done. Some answers mention Papa Parse but roll their own solution for the download part. Combining Papa Parse and FileSaver.js, you can try the following:
const dataString = Papa.unparse(data, config);
const blob = new Blob([dataString], { type: 'text/csv;charset=utf-8' });
FileSaver.saveAs(blob, 'myfile.csv');
The config options for unparse are described here.
There you go :
<!doctype html>
<html>
<head></head>
<body>
<a href='#' onclick='downloadCSV({ filename: "stock-data.csv" });'>Download CSV</a>
<script type="text/javascript">
var stockData = [
{
Symbol: "AAPL",
Company: "Apple Inc.",
Price: "132.54"
},
{
Symbol: "INTC",
Company: "Intel Corporation",
Price: "33.45"
},
{
Symbol: "GOOG",
Company: "Google Inc",
Price: "554.52"
},
];
function convertArrayOfObjectsToCSV(args) {
var result, ctr, keys, columnDelimiter, lineDelimiter, data;
data = args.data || null;
if (data == null || !data.length) {
return null;
}
columnDelimiter = args.columnDelimiter || ',';
lineDelimiter = args.lineDelimiter || '\n';
keys = Object.keys(data[0]);
result = '';
result += keys.join(columnDelimiter);
result += lineDelimiter;
data.forEach(function(item) {
ctr = 0;
keys.forEach(function(key) {
if (ctr > 0) result += columnDelimiter;
result += item[key];
ctr++;
});
result += lineDelimiter;
});
return result;
}
window.downloadCSV = function(args) {
var data, filename, link;
var csv = convertArrayOfObjectsToCSV({
data: stockData
});
if (csv == null) return;
filename = args.filename || 'export.csv';
if (!csv.match(/^data:text\/csv/i)) {
csv = 'data:text/csv;charset=utf-8,' + csv;
}
data = encodeURI(csv);
link = document.createElement('a');
link.setAttribute('href', data);
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
</script>
</body>
</html>
//It work in Chrome and IE ... I reviewed and readed a lot of answer. then i used it and tested in both ...
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
var blob = new Blob([CSV], { type: 'text/csv;charset=utf-8;' });
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", fileName);
link.style = "visibility:hidden";
}
if (navigator.msSaveBlob) { // IE 10+
link.addEventListener("click", function (event) {
var blob = new Blob([CSV], {
"type": "text/csv;charset=utf-8;"
});
navigator.msSaveBlob(blob, fileName);
}, false);
}
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
//Regards
The following is a native js solution.
function export2csv() {
let data = "";
const tableData = [];
const rows = [
['111', '222', '333'],
['aaa', 'bbb', 'ccc'],
['AAA', 'BBB', 'CCC']
];
for (const row of rows) {
const rowData = [];
for (const column of row) {
rowData.push(column);
}
tableData.push(rowData.join(","));
}
data += tableData.join("\n");
const a = document.createElement("a");
a.href = URL.createObjectURL(new Blob([data], { type: "text/csv" }));
a.setAttribute("download", "data.csv");
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
<button onclick="export2csv()">Export array to csv file</button>
One arrow function with ES6 :
const dataToCsvURI = (data) => encodeURI(
`data:text/csv;charset=utf-8,${data.map((row, index) => row.join(',')).join(`\n`)}`
);
Then :
window.open(
dataToCsvURI(
[["name1", "city_name1"/*, ...*/], ["name2", "city_name2"/*, ...*/]]
)
);
In case anyone needs this for reactjs, react-csv is there for that
A lot of roll-your-own solutions here for converting data to CSV, but just about all of them will have various caveats in terms of the type of data they will correctly format without tripping up Excel or the likes.
Why not use something proven: Papa Parse
Papa.unparse(data[, config])
Then just combine this with one of the local download solutions here eg. the one by #ArneHB looks good.
There are two questions here:
How to convert an array to csv string
How to save that string to a file
All the answers to the first question (except the one by Milimetric) here seem like an overkill. And the one by Milimetric does not cover altrenative requirements, like surrounding strings with quotes or converting arrays of objects.
Here are my takes on this:
For a simple csv one map() and a join() are enough:
var test_array = [["name1", 2, 3], ["name2", 4, 5], ["name3", 6, 7], ["name4", 8, 9], ["name5", 10, 11]];
var csv = test_array.map(function(d){
return d.join();
}).join('\n');
/* Results in
name1,2,3
name2,4,5
name3,6,7
name4,8,9
name5,10,11
This method also allows you to specify column separator other than a comma in the inner join. for example a tab: d.join('\t')
On the other hand if you want to do it properly and enclose strings in quotes "", then you can use some JSON magic:
var csv = test_array.map(function(d){
return JSON.stringify(d);
})
.join('\n')
.replace(/(^\[)|(\]$)/mg, ''); // remove opening [ and closing ]
// brackets from each line
/* would produce
"name1",2,3
"name2",4,5
"name3",6,7
"name4",8,9
"name5",10,11
if you have array of objects like :
var data = [
{"title": "Book title 1", "author": "Name1 Surname1"},
{"title": "Book title 2", "author": "Name2 Surname2"},
{"title": "Book title 3", "author": "Name3 Surname3"},
{"title": "Book title 4", "author": "Name4 Surname4"}
];
// use
var csv = data.map(function(d){
return JSON.stringify(Object.values(d));
})
.join('\n')
.replace(/(^\[)|(\]$)/mg, '');
Create a blob with the csv data .ie var blob = new Blob([data], type:"text/csv");
If the browser supports saving of blobs i.e if window.navigator.mSaveOrOpenBlob)===true, then save the csv data using: window.navigator.msSaveBlob(blob, 'filename.csv')
If the browser doesn't support saving and opening of blobs, then save csv data as:
var downloadLink = document.createElement('<a></a>');
downloadLink.attr('href', window.URL.createObjectURL(blob));
downloadLink.attr('download', filename);
downloadLink.attr('target', '_blank');
document.body.append(downloadLink);
Full Code snippet:
var filename = 'data_'+(new Date()).getTime()+'.csv';
var charset = "utf-8";
var blob = new Blob([data], {
type: "text/csv;charset="+ charset + ";"
});
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, filename);
} else {
var downloadLink = document.element('<a></a>');
downloadLink.attr('href', window.URL.createObjectURL(blob));
downloadLink.attr('download', filename);
downloadLink.attr('target', '_blank');
document.body.append(downloadLink);
downloadLink[0].click();
}
From react-admin:
function downloadCsv(csv, filename) {
const fakeLink = document.createElement('a');
fakeLink.style.display = 'none';
document.body.appendChild(fakeLink);
const blob = new Blob([csv], { type: 'text/csv' });
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
// Manage IE11+ & Edge
window.navigator.msSaveOrOpenBlob(blob, `${filename}.csv`);
} else {
fakeLink.setAttribute('href', URL.createObjectURL(blob));
fakeLink.setAttribute('download', `${filename}.csv`);
fakeLink.click();
}
};
downloadCsv('Hello World', 'any-file-name.csv');
Here's how I download CSV files on the client side in my Java GWT application. Special thanks to Xavier John for his solution. It's been verified to work in FF 24.6.0, IE 11.0.20, and Chrome 45.0.2454.99 (64-bit). I hope this saves someone a bit of time:
public class ExportFile
{
private static final String CRLF = "\r\n";
public static void exportAsCsv(String filename, List<List<String>> data)
{
StringBuilder sb = new StringBuilder();
for(List<String> row : data)
{
for(int i=0; i<row.size(); i++)
{
if(i>0) sb.append(",");
sb.append(row.get(i));
}
sb.append(CRLF);
}
generateCsv(filename, sb.toString());
}
private static native void generateCsv(String filename, String text)
/*-{
var blob = new Blob([text], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) // IE 10+
{
navigator.msSaveBlob(blob, filename);
}
else
{
var link = document.createElement("a");
if (link.download !== undefined) // feature detection
{
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}-*/;
}
Simply try this, some of the answers here are not handling unicode data and data that has comma for example date.
function downloadUnicodeCSV(filename, datasource) {
var content = '', newLine = '\r\n';
for (var _i = 0, datasource_1 = datasource; _i < datasource_1.length; _i++) {
var line = datasource_1[_i];
var i = 0;
for (var _a = 0, line_1 = line; _a < line_1.length; _a++) {
var item = line_1[_a];
var it = item.replace(/"/g, '""');
if (it.search(/("|,|\n)/g) >= 0) {
it = '"' + it + '"';
}
content += (i > 0 ? ',' : '') + it;
++i;
}
content += newLine;
}
var link = document.createElement('a');
link.setAttribute('href', 'data:text/csv;charset=utf-8,%EF%BB%BF' + encodeURIComponent(content));
link.setAttribute('download', filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
Here's an Angular friendly version:
constructor(private location: Location, private renderer: Renderer2) {}
download(content, fileName, mimeType) {
const a = this.renderer.createElement('a');
mimeType = mimeType || 'application/octet-stream';
if (navigator.msSaveBlob) {
navigator.msSaveBlob(new Blob([content], {
type: mimeType
}), fileName);
}
else if (URL && 'download' in a) {
const id = GetUniqueID();
this.renderer.setAttribute(a, 'id', id);
this.renderer.setAttribute(a, 'href', URL.createObjectURL(new Blob([content], {
type: mimeType
})));
this.renderer.setAttribute(a, 'download', fileName);
this.renderer.appendChild(document.body, a);
const anchor = this.renderer.selectRootElement(`#${id}`);
anchor.click();
this.renderer.removeChild(document.body, a);
}
else {
this.location.go(`data:application/octet-stream,${encodeURIComponent(content)}`);
}
};
The answers above work, but keep in mind that if you are opening up in the .xls format, columns ~~might~~ be separated by '\t' instead of ',', the answer https://stackoverflow.com/a/14966131/6169225 worked well for me, so long as I used .join('\t') on the arrays instead of .join(',').
I use this function to convert an string[][] to a csv file. It quotes a cell, if it contains a ", a , or other whitespace (except blanks):
/**
* Takes an array of arrays and returns a `,` sparated csv file.
* #param {string[][]} table
* #returns {string}
*/
function toCSV(table) {
return table
.map(function(row) {
return row
.map(function(cell) {
// We remove blanks and check if the column contains
// other whitespace,`,` or `"`.
// In that case, we need to quote the column.
if (cell.replace(/ /g, '').match(/[\s,"]/)) {
return '"' + cell.replace(/"/g, '""') + '"';
}
return cell;
})
.join(',');
})
.join('\n'); // or '\r\n' for windows
}
Note: does not work on Internet Explorer < 11 unless map is polyfilled.
Note: If the cells contain numbers, you can add cell=''+cell before if (cell.replace... to convert numbers to strings.
Or you can write it in one line using ES6:
t.map(r=>r.map(c=>c.replace(/ /g, '').match(/[\s,"]/)?'"'+c.replace(/"/g,'""')+'"':c).join(',')).join('\n')
Download CSV File
let csvContent = "data:text/csv;charset=utf-8,";
rows.forEach(function (rowArray) {
for (var i = 0, len = rowArray.length; i < len; i++) {
if (typeof (rowArray[i]) == 'string')
rowArray[i] = rowArray[i].replace(/<(?:.|\n)*?>/gm, '');
rowArray[i] = rowArray[i].replace(/,/g, '');
}
let row = rowArray.join(",");
csvContent += row + "\r\n"; // add carriage return
});
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "fileName.csv");
document.body.appendChild(link);
link.click();
If you are looking for a really quick solution you can also give a chance to this small library which will create and download CSV file for you: https://github.com/mbrn/filefy
Usage is very simple:
import { CsvBuilder } from 'filefy';
var csvBuilder = new CsvBuilder("user_list.csv")
.setColumns(["name", "surname"])
.addRow(["Eve", "Holt"])
.addRows([
["Charles", "Morris"],
["Tracey", "Ramos"]
])
.exportFile();
In case anyone needs this for knockout js, it works ok with basically the proposed solution:
html:
<a data-bind="attr: {download: filename, href: csvContent}">Download</a>
view model:
// for the download link
this.filename = ko.computed(function () {
return ko.unwrap(this.id) + '.csv';
}, this);
this.csvContent = ko.computed(function () {
if (!this.csvLink) {
var data = ko.unwrap(this.data),
ret = 'data:text/csv;charset=utf-8,';
ret += data.map(function (row) {
return row.join(',');
}).join('\n');
return encodeURI(ret);
}
}, this);
I added to Xavier Johns function to also include the field headers if needed, uses jQuery though. The $.each bit will need changing for a native javascript loop
function exportToCsv(filename, rows, headers = false) {
var processRow = function (row) {
row = $.map(row, function(value, index) {
return [value];
});
var finalVal = '';
for (var j = 0; j < row.length; j++) {
if(i == 0 && j == 0 && headers == true){
var ii = 0;
$.each(rows[i], function( index, value ) {
//console.log(index);
var fieldName = index === null ? '' : index.toString();
//console.log(fieldName);
var fieldResult = fieldName.replace(/"/g, '""');
//console.log(fieldResult);
if (fieldResult.search(/("|,|\n)/g) >= 0){
fieldResult = '"' + fieldResult + '"';
}
//console.log(fieldResult);
if (ii > 0){
finalVal += ',';
finalVal += fieldResult;
}else{
finalVal += fieldResult;
}
ii++;
//console.log(finalVal);
});
finalVal += '\n';
//console.log('end: '+finalVal);
}
var innerValue = row[j] === null ? '' : row[j].toString();
if (row[j] instanceof Date) {
innerValue = row[j].toLocaleString();
};
var result = innerValue.replace(/"/g, '""');
if (result.search(/("|,|\n)/g) >= 0){
result = '"' + result + '"';
}
if (j > 0){
finalVal += ',';
finalVal += result;
}else{
finalVal += result;
}
}
return finalVal + '\n';
};
var csvFile = '';
for (var i = 0; i < rows.length; i++) {
csvFile += processRow(rows[i]);
}
var blob = new Blob([csvFile], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, filename);
}else{
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}
This is a modified answer based on the accepted answer wherein the data would be coming from JSON.
JSON Data Ouptut:
0 :{emails: "SAMPLE Co., peter#samplecompany.com"}, 1:{emails: "Another CO. , ronald#another.com"}
JS:
$.getJSON('yourlink_goes_here', { if_you_have_parameters}, function(data) {
var csvContent = "data:text/csv;charset=utf-8,";
var dataString = '';
$.each(data, function(k, v) {
dataString += v.emails + "\n";
});
csvContent += dataString;
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "your_filename.csv");
document.body.appendChild(link); // Required for FF
link.click();
});
This library helps a lot: https://www.npmjs.com/package/json-to-csv-in-browser
It automatically convert an array of jsons to an csv file and it even gives you the download functionality in case you want to prompt the web user to download the csv file.
It works like a charm with very little code.
import { JsonArray, download } from 'json-to-csv-in-browser'
const arr = [
{name : ` vader`, age : 53},
{name : "what", age : 38},
{name : "ever", age : 22}
]
const jsonArray = new JsonArray(arr);
const str = jsonArray.convertToCSVstring();
download("my.csv", str);
Cheers!
EDIT: testing it a little bit more, it doesn't work that well if your values have comma on them

Javascript CSV export with BOM charset

So I have my function like below and would like to see if I am able to convert the default charset to BOM upon generation, I would like to solve the garbled code problem in excel.
exportCSVFile(headers, items, fileTitle) {
if (headers) {
items.unshift(headers);
}
// console.log(items)
// Convert Object to JSON
var jsonObject = JSON.stringify(items);
var csv = this.convertToCSV(jsonObject);
var exportedFilenmae = fileTitle + '.csv' || 'export.csv';
var blob = new Blob([csv], { type: 'text/csv;charset=windows-1252;' });
if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, exportedFilenmae);
} else {
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", exportedFilenmae);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}
The solution would be, adding BOM with UTF8
var blob = new Blob(["\uFEFF"+csv], {
type: 'text/csv; charset=utf-18'
});

How do I export csv data consistently across browsers? [duplicate]

I know there are lot of questions of this nature but I need to do this using JavaScript. I am using Dojo 1.8 and have all the attribute info in array, which looks like this:
[["name1", "city_name1", ...]["name2", "city_name2", ...]]
Any idea how I can export this to CSV on the client side?
You can do this in native JavaScript. You'll have to parse your data into correct CSV format as so (assuming you are using an array of arrays for your data as you have described in the question):
const rows = [
["name1", "city1", "some other info"],
["name2", "city2", "more info"]
];
let csvContent = "data:text/csv;charset=utf-8,";
rows.forEach(function(rowArray) {
let row = rowArray.join(",");
csvContent += row + "\r\n";
});
or the shorter way (using arrow functions):
const rows = [
["name1", "city1", "some other info"],
["name2", "city2", "more info"]
];
let csvContent = "data:text/csv;charset=utf-8,"
+ rows.map(e => e.join(",")).join("\n");
Then you can use JavaScript's window.open and encodeURI functions to download the CSV file like so:
var encodedUri = encodeURI(csvContent);
window.open(encodedUri);
Edit: If you want to give your file a specific name, you have to do things a little differently since this is not supported accessing a data URI using the window.open method. In order to achieve this, you can create a hidden <a> DOM node and set its download attribute as follows:
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "my_data.csv");
document.body.appendChild(link); // Required for FF
link.click(); // This will download the data file named "my_data.csv".
Based on the answers above I created this function that I have tested on IE 11, Chrome 36 and Firefox 29
function exportToCsv(filename, rows) {
var processRow = function (row) {
var finalVal = '';
for (var j = 0; j < row.length; j++) {
var innerValue = row[j] === null ? '' : row[j].toString();
if (row[j] instanceof Date) {
innerValue = row[j].toLocaleString();
};
var result = innerValue.replace(/"/g, '""');
if (result.search(/("|,|\n)/g) >= 0)
result = '"' + result + '"';
if (j > 0)
finalVal += ',';
finalVal += result;
}
return finalVal + '\n';
};
var csvFile = '';
for (var i = 0; i < rows.length; i++) {
csvFile += processRow(rows[i]);
}
var blob = new Blob([csvFile], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, filename);
} else {
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}
For example:
https://jsfiddle.net/jossef/m3rrLzk0/
This solution should work with Internet Explorer 10+, Edge, old and new versions of Chrome, FireFox, Safari, ++
The accepted answer won't work with IE and Safari.
// Example data given in question text
var data = [
['name1', 'city1', 'some other info'],
['name2', 'city2', 'more info']
];
// Building the CSV from the Data two-dimensional array
// Each column is separated by ";" and new line "\n" for next row
var csvContent = '';
data.forEach(function(infoArray, index) {
dataString = infoArray.join(';');
csvContent += index < data.length ? dataString + '\n' : dataString;
});
// The download function takes a CSV string, the filename and mimeType as parameters
// Scroll/look down at the bottom of this snippet to see how download is called
var download = function(content, fileName, mimeType) {
var a = document.createElement('a');
mimeType = mimeType || 'application/octet-stream';
if (navigator.msSaveBlob) { // IE10
navigator.msSaveBlob(new Blob([content], {
type: mimeType
}), fileName);
} else if (URL && 'download' in a) { //html5 A[download]
a.href = URL.createObjectURL(new Blob([content], {
type: mimeType
}));
a.setAttribute('download', fileName);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} else {
location.href = 'data:application/octet-stream,' + encodeURIComponent(content); // only this mime type is supported
}
}
download(csvContent, 'dowload.csv', 'text/csv;encoding:utf-8');
Running the code snippet will download the mock data as csv
Credits to dandavis https://stackoverflow.com/a/16377813/1350598
A minimalistic yet feature-complete solution :)
/** Convert a 2D array into a CSV string
*/
function arrayToCsv(data){
return data.map(row =>
row
.map(String) // convert every value to String
.map(v => v.replaceAll('"', '""')) // escape double colons
.map(v => `"${v}"`) // quote it
.join(',') // comma-separated
).join('\r\n'); // rows starting on new lines
}
Example:
let csv = arrayToCsv([
[1, '2', '"3"'],
[true, null, undefined],
]);
Result:
"1","2","""3"""
"true","null","undefined"
Now download it as a file:
/** Download contents as a file
* Source: https://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side
*/
function downloadBlob(content, filename, contentType) {
// Create a blob
var blob = new Blob([content], { type: contentType });
var url = URL.createObjectURL(blob);
// Create a link to download it
var pom = document.createElement('a');
pom.href = url;
pom.setAttribute('download', filename);
pom.click();
}
Download it:
downloadBlob(csv, 'export.csv', 'text/csv;charset=utf-8;')
In Chrome 35 update, download attribute behavior was changed.
https://code.google.com/p/chromium/issues/detail?id=373182
to work this in chrome, use this
var pom = document.createElement('a');
var csvContent=csv; //here we load our csv data
var blob = new Blob([csvContent],{type: 'text/csv;charset=utf-8;'});
var url = URL.createObjectURL(blob);
pom.href = url;
pom.setAttribute('download', 'foo.csv');
pom.click();
I came here looking for a bit more RFC 4180 compliance and I failed to find an implementation, so I made a (possibly inefficient) one for my own needs. I thought I would share it with everyone.
var content = [['1st title', '2nd title', '3rd title', 'another title'], ['a a a', 'bb\nb', 'cc,c', 'dd"d'], ['www', 'xxx', 'yyy', 'zzz']];
var finalVal = '';
for (var i = 0; i < content.length; i++) {
var value = content[i];
for (var j = 0; j < value.length; j++) {
var innerValue = value[j]===null?'':value[j].toString();
var result = innerValue.replace(/"/g, '""');
if (result.search(/("|,|\n)/g) >= 0)
result = '"' + result + '"';
if (j > 0)
finalVal += ',';
finalVal += result;
}
finalVal += '\n';
}
console.log(finalVal);
var download = document.getElementById('download');
download.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(finalVal));
download.setAttribute('download', 'test.csv');
Hopefully this will help someone out in the future. This combines both the encoding of the CSV along with the ability to download the file. In my example on jsfiddle. You can download the file (assuming HTML 5 browser) or view the output in the console.
UPDATE:
Chrome now appears to have lost the ability to name the file. I'm not sure what's happened or how to fix it, but whenever I use this code (including the jsfiddle), the downloaded file is now named download.csv.
People are trying to create their own csv string, which fail on edge cases, e.g. special characters, surely this is a solved problem right?
papaparse - use for JSON to CSV encoding. Papa.unparse().
import Papa from "papaparse";
const downloadCSV = (args) => {
let filename = args.filename || 'export.csv';
let columns = args.columns || null;
let csv = Papa.unparse({ data: args.data, fields: columns})
if (csv == null) return;
var blob = new Blob([csv]);
if (window.navigator.msSaveOrOpenBlob) // IE hack; see http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx
window.navigator.msSaveBlob(blob, args.filename);
else
{
var a = window.document.createElement("a");
a.href = window.URL.createObjectURL(blob, {type: "text/plain"});
a.download = filename;
document.body.appendChild(a);
a.click(); // IE: "Access is denied"; see: https://connect.microsoft.com/IE/feedback/details/797361/ie-10-treats-blob-url-as-cross-origin-and-denies-access
document.body.removeChild(a);
}
}
Example usage
downloadCSV({
filename: "filename.csv",
data: [{"a": "1", "b": "2"}],
columns: ["a","b"]
});
https://github.com/mholt/PapaParse/issues/175 - See this comment for browser support discussion.
The solution from #Default works perfect on Chrome (thanks a lot for that!) but I had a problem with IE.
Here's a solution (works on IE10):
var csvContent=data; //here we load our csv data
var blob = new Blob([csvContent],{
type: "text/csv;charset=utf-8;"
});
navigator.msSaveBlob(blob, "filename.csv")
Working for all languages
function convertToCsv(fName, rows) {
var csv = '';
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
for (var j = 0; j < row.length; j++) {
var val = row[j] === null ? '' : row[j].toString();
val = val.replace(/\t/gi, " ");
if (j > 0)
csv += '\t';
csv += val;
}
csv += '\n';
}
// for UTF-16
var cCode, bArr = [];
bArr.push(255, 254);
for (var i = 0; i < csv.length; ++i) {
cCode = csv.charCodeAt(i);
bArr.push(cCode & 0xff);
bArr.push(cCode / 256 >>> 0);
}
var blob = new Blob([new Uint8Array(bArr)], { type: 'text/csv;charset=UTF-16LE;' });
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, fName);
} else {
var link = document.createElement("a");
if (link.download !== undefined) {
var url = window.URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", fName);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
}
}
}
convertToCsv('download.csv', [
['Order', 'Language'],
['1', 'English'],
['2', 'Español'],
['3', 'Français'],
['4', 'Português'],
['5', 'čeština'],
['6', 'Slovenščina'],
['7', 'Tiếng Việt'],
['8', 'Türkçe'],
['9', 'Norsk bokmål'],
['10', 'Ελληνικά'],
['11', 'беларускі'],
['12', 'русский'],
['13', 'Українська'],
['14', 'հայերեն'],
['15', 'עִברִית'],
['16', 'اردو'],
['17', 'नेपाली'],
['18', 'हिंदी'],
['19', 'ไทย'],
['20', 'ქართული'],
['21', '中国'],
['22', '한국어'],
['23', '日本語'],
])
You can use the below piece of code to export array to CSV file using Javascript.
This handles special characters part as well
var arrayContent = [["Séjour 1, é,í,ú,ü,ű"],["Séjour 2, é,í,ú,ü,ű"]];
var csvContent = arrayContent.join("\n");
var link = window.document.createElement("a");
link.setAttribute("href", "data:text/csv;charset=utf-8,%EF%BB%BF" + encodeURI(csvContent));
link.setAttribute("download", "upload_data.csv");
link.click();
Here is the link to working jsfiddle
Old question with many good answers, but here is another simple option that relies on two popular libraries to get it done. Some answers mention Papa Parse but roll their own solution for the download part. Combining Papa Parse and FileSaver.js, you can try the following:
const dataString = Papa.unparse(data, config);
const blob = new Blob([dataString], { type: 'text/csv;charset=utf-8' });
FileSaver.saveAs(blob, 'myfile.csv');
The config options for unparse are described here.
There you go :
<!doctype html>
<html>
<head></head>
<body>
<a href='#' onclick='downloadCSV({ filename: "stock-data.csv" });'>Download CSV</a>
<script type="text/javascript">
var stockData = [
{
Symbol: "AAPL",
Company: "Apple Inc.",
Price: "132.54"
},
{
Symbol: "INTC",
Company: "Intel Corporation",
Price: "33.45"
},
{
Symbol: "GOOG",
Company: "Google Inc",
Price: "554.52"
},
];
function convertArrayOfObjectsToCSV(args) {
var result, ctr, keys, columnDelimiter, lineDelimiter, data;
data = args.data || null;
if (data == null || !data.length) {
return null;
}
columnDelimiter = args.columnDelimiter || ',';
lineDelimiter = args.lineDelimiter || '\n';
keys = Object.keys(data[0]);
result = '';
result += keys.join(columnDelimiter);
result += lineDelimiter;
data.forEach(function(item) {
ctr = 0;
keys.forEach(function(key) {
if (ctr > 0) result += columnDelimiter;
result += item[key];
ctr++;
});
result += lineDelimiter;
});
return result;
}
window.downloadCSV = function(args) {
var data, filename, link;
var csv = convertArrayOfObjectsToCSV({
data: stockData
});
if (csv == null) return;
filename = args.filename || 'export.csv';
if (!csv.match(/^data:text\/csv/i)) {
csv = 'data:text/csv;charset=utf-8,' + csv;
}
data = encodeURI(csv);
link = document.createElement('a');
link.setAttribute('href', data);
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
</script>
</body>
</html>
//It work in Chrome and IE ... I reviewed and readed a lot of answer. then i used it and tested in both ...
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
var blob = new Blob([CSV], { type: 'text/csv;charset=utf-8;' });
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", fileName);
link.style = "visibility:hidden";
}
if (navigator.msSaveBlob) { // IE 10+
link.addEventListener("click", function (event) {
var blob = new Blob([CSV], {
"type": "text/csv;charset=utf-8;"
});
navigator.msSaveBlob(blob, fileName);
}, false);
}
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
//Regards
The following is a native js solution.
function export2csv() {
let data = "";
const tableData = [];
const rows = [
['111', '222', '333'],
['aaa', 'bbb', 'ccc'],
['AAA', 'BBB', 'CCC']
];
for (const row of rows) {
const rowData = [];
for (const column of row) {
rowData.push(column);
}
tableData.push(rowData.join(","));
}
data += tableData.join("\n");
const a = document.createElement("a");
a.href = URL.createObjectURL(new Blob([data], { type: "text/csv" }));
a.setAttribute("download", "data.csv");
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
<button onclick="export2csv()">Export array to csv file</button>
One arrow function with ES6 :
const dataToCsvURI = (data) => encodeURI(
`data:text/csv;charset=utf-8,${data.map((row, index) => row.join(',')).join(`\n`)}`
);
Then :
window.open(
dataToCsvURI(
[["name1", "city_name1"/*, ...*/], ["name2", "city_name2"/*, ...*/]]
)
);
In case anyone needs this for reactjs, react-csv is there for that
A lot of roll-your-own solutions here for converting data to CSV, but just about all of them will have various caveats in terms of the type of data they will correctly format without tripping up Excel or the likes.
Why not use something proven: Papa Parse
Papa.unparse(data[, config])
Then just combine this with one of the local download solutions here eg. the one by #ArneHB looks good.
There are two questions here:
How to convert an array to csv string
How to save that string to a file
All the answers to the first question (except the one by Milimetric) here seem like an overkill. And the one by Milimetric does not cover altrenative requirements, like surrounding strings with quotes or converting arrays of objects.
Here are my takes on this:
For a simple csv one map() and a join() are enough:
var test_array = [["name1", 2, 3], ["name2", 4, 5], ["name3", 6, 7], ["name4", 8, 9], ["name5", 10, 11]];
var csv = test_array.map(function(d){
return d.join();
}).join('\n');
/* Results in
name1,2,3
name2,4,5
name3,6,7
name4,8,9
name5,10,11
This method also allows you to specify column separator other than a comma in the inner join. for example a tab: d.join('\t')
On the other hand if you want to do it properly and enclose strings in quotes "", then you can use some JSON magic:
var csv = test_array.map(function(d){
return JSON.stringify(d);
})
.join('\n')
.replace(/(^\[)|(\]$)/mg, ''); // remove opening [ and closing ]
// brackets from each line
/* would produce
"name1",2,3
"name2",4,5
"name3",6,7
"name4",8,9
"name5",10,11
if you have array of objects like :
var data = [
{"title": "Book title 1", "author": "Name1 Surname1"},
{"title": "Book title 2", "author": "Name2 Surname2"},
{"title": "Book title 3", "author": "Name3 Surname3"},
{"title": "Book title 4", "author": "Name4 Surname4"}
];
// use
var csv = data.map(function(d){
return JSON.stringify(Object.values(d));
})
.join('\n')
.replace(/(^\[)|(\]$)/mg, '');
Create a blob with the csv data .ie var blob = new Blob([data], type:"text/csv");
If the browser supports saving of blobs i.e if window.navigator.mSaveOrOpenBlob)===true, then save the csv data using: window.navigator.msSaveBlob(blob, 'filename.csv')
If the browser doesn't support saving and opening of blobs, then save csv data as:
var downloadLink = document.createElement('<a></a>');
downloadLink.attr('href', window.URL.createObjectURL(blob));
downloadLink.attr('download', filename);
downloadLink.attr('target', '_blank');
document.body.append(downloadLink);
Full Code snippet:
var filename = 'data_'+(new Date()).getTime()+'.csv';
var charset = "utf-8";
var blob = new Blob([data], {
type: "text/csv;charset="+ charset + ";"
});
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, filename);
} else {
var downloadLink = document.element('<a></a>');
downloadLink.attr('href', window.URL.createObjectURL(blob));
downloadLink.attr('download', filename);
downloadLink.attr('target', '_blank');
document.body.append(downloadLink);
downloadLink[0].click();
}
From react-admin:
function downloadCsv(csv, filename) {
const fakeLink = document.createElement('a');
fakeLink.style.display = 'none';
document.body.appendChild(fakeLink);
const blob = new Blob([csv], { type: 'text/csv' });
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
// Manage IE11+ & Edge
window.navigator.msSaveOrOpenBlob(blob, `${filename}.csv`);
} else {
fakeLink.setAttribute('href', URL.createObjectURL(blob));
fakeLink.setAttribute('download', `${filename}.csv`);
fakeLink.click();
}
};
downloadCsv('Hello World', 'any-file-name.csv');
Here's how I download CSV files on the client side in my Java GWT application. Special thanks to Xavier John for his solution. It's been verified to work in FF 24.6.0, IE 11.0.20, and Chrome 45.0.2454.99 (64-bit). I hope this saves someone a bit of time:
public class ExportFile
{
private static final String CRLF = "\r\n";
public static void exportAsCsv(String filename, List<List<String>> data)
{
StringBuilder sb = new StringBuilder();
for(List<String> row : data)
{
for(int i=0; i<row.size(); i++)
{
if(i>0) sb.append(",");
sb.append(row.get(i));
}
sb.append(CRLF);
}
generateCsv(filename, sb.toString());
}
private static native void generateCsv(String filename, String text)
/*-{
var blob = new Blob([text], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) // IE 10+
{
navigator.msSaveBlob(blob, filename);
}
else
{
var link = document.createElement("a");
if (link.download !== undefined) // feature detection
{
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}-*/;
}
Simply try this, some of the answers here are not handling unicode data and data that has comma for example date.
function downloadUnicodeCSV(filename, datasource) {
var content = '', newLine = '\r\n';
for (var _i = 0, datasource_1 = datasource; _i < datasource_1.length; _i++) {
var line = datasource_1[_i];
var i = 0;
for (var _a = 0, line_1 = line; _a < line_1.length; _a++) {
var item = line_1[_a];
var it = item.replace(/"/g, '""');
if (it.search(/("|,|\n)/g) >= 0) {
it = '"' + it + '"';
}
content += (i > 0 ? ',' : '') + it;
++i;
}
content += newLine;
}
var link = document.createElement('a');
link.setAttribute('href', 'data:text/csv;charset=utf-8,%EF%BB%BF' + encodeURIComponent(content));
link.setAttribute('download', filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
Here's an Angular friendly version:
constructor(private location: Location, private renderer: Renderer2) {}
download(content, fileName, mimeType) {
const a = this.renderer.createElement('a');
mimeType = mimeType || 'application/octet-stream';
if (navigator.msSaveBlob) {
navigator.msSaveBlob(new Blob([content], {
type: mimeType
}), fileName);
}
else if (URL && 'download' in a) {
const id = GetUniqueID();
this.renderer.setAttribute(a, 'id', id);
this.renderer.setAttribute(a, 'href', URL.createObjectURL(new Blob([content], {
type: mimeType
})));
this.renderer.setAttribute(a, 'download', fileName);
this.renderer.appendChild(document.body, a);
const anchor = this.renderer.selectRootElement(`#${id}`);
anchor.click();
this.renderer.removeChild(document.body, a);
}
else {
this.location.go(`data:application/octet-stream,${encodeURIComponent(content)}`);
}
};
The answers above work, but keep in mind that if you are opening up in the .xls format, columns ~~might~~ be separated by '\t' instead of ',', the answer https://stackoverflow.com/a/14966131/6169225 worked well for me, so long as I used .join('\t') on the arrays instead of .join(',').
I use this function to convert an string[][] to a csv file. It quotes a cell, if it contains a ", a , or other whitespace (except blanks):
/**
* Takes an array of arrays and returns a `,` sparated csv file.
* #param {string[][]} table
* #returns {string}
*/
function toCSV(table) {
return table
.map(function(row) {
return row
.map(function(cell) {
// We remove blanks and check if the column contains
// other whitespace,`,` or `"`.
// In that case, we need to quote the column.
if (cell.replace(/ /g, '').match(/[\s,"]/)) {
return '"' + cell.replace(/"/g, '""') + '"';
}
return cell;
})
.join(',');
})
.join('\n'); // or '\r\n' for windows
}
Note: does not work on Internet Explorer < 11 unless map is polyfilled.
Note: If the cells contain numbers, you can add cell=''+cell before if (cell.replace... to convert numbers to strings.
Or you can write it in one line using ES6:
t.map(r=>r.map(c=>c.replace(/ /g, '').match(/[\s,"]/)?'"'+c.replace(/"/g,'""')+'"':c).join(',')).join('\n')
Download CSV File
let csvContent = "data:text/csv;charset=utf-8,";
rows.forEach(function (rowArray) {
for (var i = 0, len = rowArray.length; i < len; i++) {
if (typeof (rowArray[i]) == 'string')
rowArray[i] = rowArray[i].replace(/<(?:.|\n)*?>/gm, '');
rowArray[i] = rowArray[i].replace(/,/g, '');
}
let row = rowArray.join(",");
csvContent += row + "\r\n"; // add carriage return
});
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "fileName.csv");
document.body.appendChild(link);
link.click();
If you are looking for a really quick solution you can also give a chance to this small library which will create and download CSV file for you: https://github.com/mbrn/filefy
Usage is very simple:
import { CsvBuilder } from 'filefy';
var csvBuilder = new CsvBuilder("user_list.csv")
.setColumns(["name", "surname"])
.addRow(["Eve", "Holt"])
.addRows([
["Charles", "Morris"],
["Tracey", "Ramos"]
])
.exportFile();
In case anyone needs this for knockout js, it works ok with basically the proposed solution:
html:
<a data-bind="attr: {download: filename, href: csvContent}">Download</a>
view model:
// for the download link
this.filename = ko.computed(function () {
return ko.unwrap(this.id) + '.csv';
}, this);
this.csvContent = ko.computed(function () {
if (!this.csvLink) {
var data = ko.unwrap(this.data),
ret = 'data:text/csv;charset=utf-8,';
ret += data.map(function (row) {
return row.join(',');
}).join('\n');
return encodeURI(ret);
}
}, this);
I added to Xavier Johns function to also include the field headers if needed, uses jQuery though. The $.each bit will need changing for a native javascript loop
function exportToCsv(filename, rows, headers = false) {
var processRow = function (row) {
row = $.map(row, function(value, index) {
return [value];
});
var finalVal = '';
for (var j = 0; j < row.length; j++) {
if(i == 0 && j == 0 && headers == true){
var ii = 0;
$.each(rows[i], function( index, value ) {
//console.log(index);
var fieldName = index === null ? '' : index.toString();
//console.log(fieldName);
var fieldResult = fieldName.replace(/"/g, '""');
//console.log(fieldResult);
if (fieldResult.search(/("|,|\n)/g) >= 0){
fieldResult = '"' + fieldResult + '"';
}
//console.log(fieldResult);
if (ii > 0){
finalVal += ',';
finalVal += fieldResult;
}else{
finalVal += fieldResult;
}
ii++;
//console.log(finalVal);
});
finalVal += '\n';
//console.log('end: '+finalVal);
}
var innerValue = row[j] === null ? '' : row[j].toString();
if (row[j] instanceof Date) {
innerValue = row[j].toLocaleString();
};
var result = innerValue.replace(/"/g, '""');
if (result.search(/("|,|\n)/g) >= 0){
result = '"' + result + '"';
}
if (j > 0){
finalVal += ',';
finalVal += result;
}else{
finalVal += result;
}
}
return finalVal + '\n';
};
var csvFile = '';
for (var i = 0; i < rows.length; i++) {
csvFile += processRow(rows[i]);
}
var blob = new Blob([csvFile], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, filename);
}else{
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}
This is a modified answer based on the accepted answer wherein the data would be coming from JSON.
JSON Data Ouptut:
0 :{emails: "SAMPLE Co., peter#samplecompany.com"}, 1:{emails: "Another CO. , ronald#another.com"}
JS:
$.getJSON('yourlink_goes_here', { if_you_have_parameters}, function(data) {
var csvContent = "data:text/csv;charset=utf-8,";
var dataString = '';
$.each(data, function(k, v) {
dataString += v.emails + "\n";
});
csvContent += dataString;
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "your_filename.csv");
document.body.appendChild(link); // Required for FF
link.click();
});
This library helps a lot: https://www.npmjs.com/package/json-to-csv-in-browser
It automatically convert an array of jsons to an csv file and it even gives you the download functionality in case you want to prompt the web user to download the csv file.
It works like a charm with very little code.
import { JsonArray, download } from 'json-to-csv-in-browser'
const arr = [
{name : ` vader`, age : 53},
{name : "what", age : 38},
{name : "ever", age : 22}
]
const jsonArray = new JsonArray(arr);
const str = jsonArray.convertToCSVstring();
download("my.csv", str);
Cheers!
EDIT: testing it a little bit more, it doesn't work that well if your values have comma on them

Create CSV and open with JS not working in IE, Chrome

I am creating a CSV file from a js object by supplying a filename, comma separated headers, and a data key-value object. However, when I go to download the file, I am facing the following issues:
Chrome: File downloads, but the file is unnamed and has no file extension
IE: File doesn't even download.
Here is my JS code:
function createCSV(filename, headers, data) {
var csvContent = "data:text/csv;charset=utf-8," + headers;
data.forEach(function(d, index) {
var dataString = "";
var i = 0;
for ( var key in d) {
if (d[key] == 'null')
dataString += '\"\"';
else
dataString += "\"=\"\"" + d[key] + "\"\"\"";
if (i < Object.keys(d).length - 1)
dataString += ",";
i++;
}
if (index < data.length)
csvContent += "\n";
csvContent += dataString;
});
var filename = filename + ".csv"
var link = document.createElement("a");
link.setAttribute("href", encodeURI(csvContent));
link.setAttribute("download", filename);
actuateLink(link);
}
function actuateLink(link)
{
var allowDefaultAction = true;
if (link.click)
{
link.click();
return;
}
else if (document.createEvent)
{
var e = document.createEvent('MouseEvents');
e.initEvent('click', true, true);
allowDefaultAction = link.dispatchEvent(e);
}
if (allowDefaultAction)
{
var f = document.createElement('form');
f.action = link.href;
document.body.appendChild(f);
f.submit();
}
}
See fixes for specific browsers below:
function downloadFile(filename, csvContent) {
var blob = new Blob([csvContent]);
var needsClick = true;
var browser = "";
if ( window.webkitURL ) {
browser = "CHROME";
var link = document.createElement("a");
link.setAttribute("href", "data:text/csv;charset=utf-8," + encodeURI(csvContent));
link.setAttribute("target", "_blank");
link.setAttribute("download", filename);
link.click();
} else {
if (document.createEvent) {
browser = "FIREFOX";
var link = document.createElement("a");
link.setAttribute("href", encodeURI("data:text/csv;charset=utf-8," + csvContent));
link.setAttribute("download", filename);
var e = document.createEvent('MouseEvents');
e.initEvent('click', true, true);
needsClick = link.dispatchEvent(e);
}
if(needsClick) {
if(window.navigator.msSaveBlob != undefined){
browser = "IE";
window.navigator.msSaveBlob(blob, filename);
}
}
}
console.log(browser); }
You can fix this problem, at least for Chrome, with the proposed answers to this question.
I do not know an answer for Internet Explorer or any other browser, however.

Categories

Resources