30

Hi I am trying to export a file as .csv file, so that when the user clicks on the download button, the browser would automatically download the file as .csv. I also want to be able to set a name for the .csv file to be exported

I am using javascript to do this

Code is below:

 function ConvertToCSV(objArray) {
            var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
            var str = '';

            for (var i = 0; i < array.length; i++) {
                var line = '';
            for (var index in array[i]) {
                if (line != '') line += ','

                line += array[i][index];
            }

            str += line + '\r\n';
        }

        return str;
    }

    // Example
    $(document).ready(function () {

        // Create Object
        var items = [
              { "name": "Item 1", "color": "Green", "size": "X-Large" },
              { "name": "Item 2", "color": "Green", "size": "X-Large" },
              { "name": "Item 3", "color": "Green", "size": "X-Large" }];

        // Convert Object to JSON
        var jsonObject = JSON.stringify(items);

        // Display JSON
        $('#json').text(jsonObject);

        // Convert JSON to CSV & Display CSV
        $('#csv').text(ConvertToCSV(jsonObject));

        $("#download").click(function() {
            alert("2");
            var csv = ConvertToCSV(jsonObject);
            window.open("data:text/csv;charset=utf-8," + escape(csv))
            ///////


        });

    });

Please advise on this My Boss is breathing down my neck on this issue

Please help

Pranav Kale
  • 589
  • 1
  • 4
  • 12
Samuel Tang
  • 333
  • 1
  • 4
  • 8

6 Answers6

35

I have written a solution in this thread: how to set a file name using window.open

This is the simple solution:

 $("#download_1").click(function() {
var json_pre = '[{"Id":1,"UserName":"Sam Smith"},{"Id":2,"UserName":"Fred Frankly"},{"Id":1,"UserName":"Zachary Zupers"}]';
var json = $.parseJSON(json_pre);

var csv = JSON2CSV(json);
var downloadLink = document.createElement("a");
var blob = new Blob(["\ufeff", csv]);
var url = URL.createObjectURL(blob);
downloadLink.href = url;
downloadLink.download = "data.csv";

document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
});

JSON2CSV function

function JSON2CSV(objArray) {
    var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
    var str = '';
    var line = '';

    if ($("#labels").is(':checked')) {
        var head = array[0];
        if ($("#quote").is(':checked')) {
            for (var index in array[0]) {
                var value = index + "";
                line += '"' + value.replace(/"/g, '""') + '",';
            }
        } else {
            for (var index in array[0]) {
                line += index + ',';
            }
        }

        line = line.slice(0, -1);
        str += line + '\r\n';
    }

    for (var i = 0; i < array.length; i++) {
        var line = '';

        if ($("#quote").is(':checked')) {
            for (var index in array[i]) {
                var value = array[i][index] + "";
                line += '"' + value.replace(/"/g, '""') + '",';
            }
        } else {
            for (var index in array[i]) {
                line += array[i][index] + ',';
            }
        }

        line = line.slice(0, -1);
        str += line + '\r\n';
    }
    return str;
}
Community
  • 1
  • 1
Jewel
  • 2,053
  • 21
  • 21
30

in modern browsers there is a new attribute in anchors.

download

http://caniuse.com/download

so instead of using

window.open("data:text/csv;charset=utf-8," + escape(csv))

create a download link:

<a href="data:text/csv;charset=utf-8,'+escape(csv)+'" download="filename.csv">download</a>

another solution is to use php

EDIT

i don't use jQuery, but you need to edit your code to add the download link with something like that in your function.

var csv=ConvertToCSV(jsonObject),
a=document.createElement('a');
a.textContent='download';
a.download="myFileName.csv";
a.href='data:text/csv;charset=utf-8,'+escape(csv);
document.body.appendChild(a);
cocco
  • 15,256
  • 6
  • 53
  • 73
  • Hi But I can't download the content I want is there more codes I need to edit – Samuel Tang Jul 10 '13 at 07:25
  • what you mean ? use onefo the supporting browsers (chrome for example).with javascript dynamically insert the href data and the download filename. – cocco Jul 10 '13 at 07:25
  • '+escape(csv)+' this is what I see in the excel file – Samuel Tang Jul 10 '13 at 07:32
  • Because you might have copied the html to the page. He is suggesting you "create" the csv link using javascript, thus '+escape(csv)+' is going to break out of the single quoted string of html and insert the escaped csv in the href link. – Dustin Graham Jan 28 '14 at 22:17
9

Try these Examples:

Example 1:

JsonArray = [{
    "AccountNumber": "1234",
    "AccountName": "abc",
    "port": "All",
    "source": "sg-a78c04f8"

}, {
    "Account Number": "1234",
    "Account Name": "abc",
    "port": 22,
    "source": "0.0.0.0/0",
}]

JsonFields = ["Account Number","Account Name","port","source"]

function JsonToCSV(){
    var csvStr = JsonFields.join(",") + "\n";

    JsonArray.forEach(element => {
        AccountNumber = element.AccountNumber;
        AccountName   = element.AccountName;
        port          = element.port
        source        = element.source

        csvStr += AccountNumber + ',' + AccountName + ','  + port + ',' + source + "\n";
        })
        return csvStr;
}

You can download the csv file using the following code :

function downloadCSV(csvStr) {

    var hiddenElement = document.createElement('a');
    hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csvStr);
    hiddenElement.target = '_blank';
    hiddenElement.download = 'output.csv';
    hiddenElement.click();
}
Scott
  • 639
  • 7
  • 18
YouBee
  • 1,366
  • 10
  • 12
5

I just wanted to add some code here for people in the future since I was trying to export JSON to a CSV document and download it.

I use $.getJSON to pull json data from an external page, but if you have a basic array, you can just use that.

This uses Christian Landgren's code to create the csv data.

$(document).ready(function() {
    var JSONData = $.getJSON("GetJsonData.php", function(data) {
        var items = data;
        const replacer = (key, value) => value === null ? '' : value; // specify how you want to handle null values here
        const header = Object.keys(items[0]);
        let csv = items.map(row => header.map(fieldName => JSON.stringify(row[fieldName], replacer)).join(','));
        csv.unshift(header.join(','));
        csv = csv.join('\r\n');

        //Download the file as CSV
        var downloadLink = document.createElement("a");
        var blob = new Blob(["\ufeff", csv]);
        var url = URL.createObjectURL(blob);
        downloadLink.href = url;
        downloadLink.download = "DataDump.csv";  //Name the file here
        document.body.appendChild(downloadLink);
        downloadLink.click();
        document.body.removeChild(downloadLink);
    });
});

Edit: It's worth noting that JSON.stringify will escape quotes in quotes by adding \". If you view the CSV in excel, it doesn't like that as an escape character.

You can add .replace(/\\"/g, '""') to the end of JSON.stringify(row[fieldName], replacer) to display this properly in excel (this will replace \" with "" which is what excel prefers).

Full Line: JSON.stringify(row[fieldName], replacer).replace(/\\"/g, '""')

user1274820
  • 6,145
  • 2
  • 31
  • 66
3

One-liner function for simple JSON with static titles

Assuming arr is JSON array, you can also replace the first string with comma separated titles end with \n

arr.reduce((acc, curr) => (`${acc}${Object.values(curr).join(",")}\n`), "")

Or with the window.open function mentioned before

window.open(`data:text/csv;charset=utf-8,${arr.reduce((acc, curr) => (`${acc}${Object.values(curr).join(",")}\n`), "")}`)

You should also consider escape the strings or replace the , to avoid extra cells

g.e.manor
  • 476
  • 5
  • 12
0

If your data comes from a SQL Database, all your lines should have the same structure, but if coming from a NoSQL Database you could have trouble using standard answers. I elaborated on above JSON2CSV for such a scenario. Json data example

  [ {"meal":2387,"food":"beaf"},
    {"meal":2387,"food":"apple","peeled":"yes", "speed":"fast" },
    {"meal":2387,"food":"pear", "speed":"slow", "peeled":"yes" } ]

Answer

"meal","food","peeled","speed"
"2387","beaf","",""
"2387","apple","yes","fast"
"2387","pear","yes","slow"

Code for headers and double quotes for simplicity.

function JSON2CSV(objArray) {
  var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;

  var str = '';
  var line = '';

  // get all distinct keys      
  let titles = [];
  for (var i = 0; i < array.length; i++) {
    let obj = array[i];
    Object.entries(obj).forEach(([key,value])=>{
      //console.log('key=', key, "   val=", value );
      if (titles.includes(key) ) {
        // console.log (key , 'exists');
        null;
      }
      else {
        titles.push(key);
      }
    })
  }
  let htext =  '"' + titles.join('","') + '"';
  console.log('header:', htext);
  // add to str
  str += htext + '\r\n';
  //
  // lines
  for (var i = 0; i < array.length; i++) {
    var line = '';
    // get values by header order
    for (var j = 0; j < titles.length; j++) {
      // match keys with current header
      let obj = array[i];
      let keyfound = 0;    
      // each key/value pair
      Object.entries(obj).forEach(([key,value])=>{
        if (key == titles[j]) {
          // console.log('equal tit=', titles[j] , ' e key ', key ); // matched key with header
          line += ',"' + value +  '"';
          keyfound = 1; 
          return false;
        }

      })
      if (keyfound == 0) {
        line += ',"'  +  '"';   // add null value for this key
      } // end loop of header values

    }

    str += line.slice(1) + '\r\n';
  }
  return str;
}