Reputation: 7729
There is a lot of info on how to create a CSV file with Javascript here on Stack Overflow. But I'm struggling to find a way to create semicolon separated data and be able to set the file name on download.
Below is a simplified version of my code. The last lines demonstrates the problem: CSV with colon works well. CSV with semi colon fails, the browser will not download the file (Chrome says "network error").
const arrayToCsvFile = (dataArray, delimiter, filename) => {
const csv = createCsv(dataArray, delimiter);
exportCsvToFile(csv, filename, delimiter);
};
const createCsv = (rows, delimiter) => {
let returnStr = "";
rows.forEach(row => {
row.forEach(field => {
returnStr += field + delimiter;
});
returnStr += "\r\n";
});
return returnStr;
};
const exportCsvToFile = (csvData, filename, delimiter) => {
csvData = "data:text/csv;charset=utf-8" + delimiter + csvData;
const encodedUri = encodeURI(csvData);
// Trick to set filename
const link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", filename);
document.body.appendChild(link); // Required for Firefox(?)
link.click();
};
const testData = [["a", "b", "c"], ["1", "2", "3"]];
// Line below works
// arrayToCsvFile(testData, ",", "myCustomFileNameWithCommaSep.csv");
// This does not work - browser fails to download file.
arrayToCsvFile(testData, ";", "myCustomFileNameWithSemiSep.csv");
Upvotes: 1
Views: 4313
Reputation: 14561
csvData = "data:text/csv;charset=utf-8" + delimiter + csvData;
Notice that delimiter parameter gets appended here, which is semicolon in your case. Just change that to comma and it should work fine:
csvData = "data:text/csv;charset=utf-8," + csvData;
const arrayToCsvFile = (dataArray, delimiter, filename) => {
const csv = createCsv(dataArray, delimiter);
exportCsvToFile(csv, filename, delimiter);
};
const createCsv = (rows, delimiter) => {
let returnStr = "";
rows.forEach(row => {
row.forEach(field => {
returnStr += field + delimiter;
});
returnStr += "\r\n";
});
return returnStr;
};
const exportCsvToFile = (csvData, filename, delimiter) => {
// FIXED: Comma instead of semicolon
csvData = "data:text/csv;charset=utf-8," + csvData;
const encodedUri = encodeURI(csvData);
// Trick to set filename
const link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", filename);
document.body.appendChild(link); // Required for Firefox(?)
link.click();
};
const testData = [["a", "b", "c"], ["1", "2", "3"]];
// Line below works
// arrayToCsvFile(testData, ",", "myCustomFileNameWithCommaSep.csv");
// This will now also work!
arrayToCsvFile(testData, ";", "myCustomFileNameWithSemiSep.csv");
Upvotes: 2
Reputation: 944084
Look at the definition of the data URI scheme.
data:[<media type>][;base64],<data>
…
The data, separated from the preceding part by a comma (,).
Now look at your code:
csvData = "data:text/csv;charset=utf-8" + delimiter + csvData;
You're reusing the delimiter you use in your CSV for your data URI, but the data URI delimited must be a comma!
Use a comma there:
csvData = "data:text/csv;charset=utf-8," + csvData;
Upvotes: 2