12

I have a field called csvdata that contains an array of the following format:

[
    [1,2,3],
    [4,5,6],
    [7,8,9]
]

I'm trying to download a CSV file of this data. I'm using Vue so it looks like:

<button type="button" class="btn btn-info action_btn" v-on:click="downloadCSVData">
      Download
</button>

How should the downloadCSVData function look like?

1
  • you need a backend scripting language such as PHP to process that array into a downloadable file. Commented Oct 8, 2019 at 19:26

3 Answers 3

28

I think you can create a method like so, assuming csvdata is a data property accessible by this in your Vue component:

downloadCSVData() => {
    let csv = 'Put,Column,Titles,Here\n';
    this.csvdata.forEach((row) => {
            csv += row.join(',');
            csv += "\n";
    });
 
    const anchor = document.createElement('a');
    anchor.href = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csv);
    anchor.target = '_blank';
    anchor.download = 'nameYourFileHere.csv';
    anchor.click();
}

Sign up to request clarification or add additional context in comments.

5 Comments

encodeURI worked for a small amount of data (~2 rows of 8 columns). But following this with encodeURIComponent worked for way more data.
@JoshMorel you're right. I'll update my answer. Here's some documentation on the difference: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Elegant solution - Very nice
Error in v-on handler: "TypeError: row.join is not a function"
@FernandoTorres the original post states that csvdata is a two-dimensional array. So each row is an array. Array, in Javascript, has a built-in method called join. In that context, row.join will work. If csvdata were a one-dimensional array, then each "row" would be a single Boolean or String or Number or Object, none of which have a built-in method called join and so you'd get the TypeError you describe.
2

Here is the working code to download a csv file in vue

This sample code converts array of objects to perfect csv file with headers call the function exportCSVFile(headers, items, fileTitle)

headers = { name: 'Name' // formatted column name, age: 'Age' }

items = [ { name: 'Joo', age: 21 }, { name: 'ant', age: 20 } ]

filename = 'somefilename.csv'

function convertToCSV(objArray) {
  const array = typeof objArray !== 'object' ? JSON.parse(objArray) : objArray;
  let str = '';
  for (let i = 0; i < array.length; i++) { // eslint-disable-line
    let line = '';
    for (const index in array[i]) { // eslint-disable-line
      if (line !== '') line += ',';
      line += array[i][index];
    }
    str += line + '\r\n'; // eslint-disable-line
  }
  return str;
}

function exportCSVFile(headers, items, fileTitle) {
  if (headers) {
    items.unshift(headers);
  }
  const jsonObject = JSON.stringify(items);
  const csv = convertToCSV(jsonObject);
  const exportedFilenmae = fileTitle + '.csv' || 'export.csv'; // eslint-disable-line
  const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
  if (navigator.msSaveBlob) { // IE 10+
    navigator.msSaveBlob(blob, exportedFilenmae);
  } else {
    const link = document.createElement('a');
    if (link.download !== undefined) {
      const 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);
    }
  }
}

export default exportCSVFile;

If the given value is 2d array, just use this function

function downloadCSVData () {
    var array = [
    [1,2,3],
    [4,5,6],
    [7,8,9]
    ];
    var str = '';
    for (var i = 0; i < array.length; i++) { 
    let line = '';
    line = array[i].join(",");
    str += line + '\r\n';
    }
    var blob = new Blob([str], { type: 'text/csv;charset=utf-8;' });

    var link = document.createElement('a');
    var url = URL.createObjectURL(blob);
    link.setAttribute('href', url);
    link.setAttribute('download', 'csvfilename.csv');
    link.style.visibility = 'hidden';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

Comments

1
  1. Convert the Array to text. (let data = [[1,2,3], [4,5,6], [7,8,9]].join('\r\n').toString())
  2. Convert the text to base64. (let encoded_data = btoa(data))
  3. Create an iFrame and set its src = the encoded data. let iframe = document.createElement('iframe'); iframe.src = "data:application/octet-stream;base64," + encoded_data
  4. Append the iframe to the document's body: document.body.appendChild(iframe).

There's some drawbacks to this approach though:

  1. Content Security Policy can block step 4. You have control over CSP in your page, but don't sacrifice security for easy code.
  2. The file will always be named "download" with no file extension.

A better approach would be to create a temporary file on the server and provide the user a link to that file.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.