HoffZ
HoffZ

Reputation: 7729

How to create semicolon separated CSV in Javascript with custom file name?

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

Answers (2)

Nisarg Shah
Nisarg Shah

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

Quentin
Quentin

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

Related Questions