limeygent
limeygent

Reputation: 426

JS: convert 2D object with keys to transposed csv

I have an ajax call that returns a 2D object and I want to be able to convert it into a .csv file for the user to download.

The php code: echo json_encode($results);

The js function, right now has console.log (JSON.parse(res)); so I can verify the contents.

The console log shows:

Object {color: Object, animal: Object}
  color: Object
    1: "red"
    2: "white"
    3: "blue"
  animal: Object
    1: "cat"
    2: "dog"
    3: "mouse  

Each of the inner objects always has the same number of elements (in this case, 3)

I would like to convert this to a csv and then download. The first line of the csv would contain the outer object keys (color, animal) The csv would end up like this:

"color, animal"
"red, cat"
"white, dog"
"blue, mouse"

With the solutions I've looked at, they append a joined version of the object to each row. I need to transpose the data vertically.

I think that I need to step through each inner object (get the nth element of each one, get the n+1th element of each one etc) and build my own csv strings, but that seems awfully clunky.

Any nifty array/object functions out there that can help me?

I am able to create and download a .csv file, it's just this data transpose logic that has me stuck.

EDIT: I am not trying to convert a csv string to an array, nor am I trying to transpose a 2D array (it's a 2D object).

Clarification In my ajax call to the php file, I am sending an array of ["color", "animal"] which is derived from user input. The php file reads this array and gathers data based on this array. Once the data has been gathered, it returns a 2D array, the inner array being the new data. Thus:

[color[red, white, blue], animal[cat,dog,mouse]]

Upvotes: 0

Views: 500

Answers (3)

Dickens A S
Dickens A S

Reputation: 4054

From your question you are saying console.log($result) that means you are trying to fetch it via AJAX I assume.

I would recommend you to not create CSV on client side JavaScript, do it from your PHP code, simply put a hyperlink for your php file which contains the CSV creation code with Content-Type and Content-Disposition therefore the browser will directly show the file save dialog box.

See this answer File is not being downloaded when requested through Ajax using JQuery

Simply put a hyperlink

<a href="admin_ajax.php">Download</a>

Refer Force Download CSV File
Refer Create a CSV File for a user in PHP

-- EDIT --

Client side CSV is possible.

But the reason I am recommending the server side CSV.

  • Size of CSV can be bigger which might make your client size JSON based loop consume memory and might reduce the browser performance.
  • Server side compression options like GZIP or reverse proxy compressed traffic is easy and it will be automatically decompressed by browser, but client side decompression could be trivial
  • In case if you want to provide an additional option of PDF or Rich XLSX file download option it may not be possible as easy in javascript.

Upvotes: 1

Kaiido
Kaiido

Reputation: 137171

You could try something like that :

var rep = JSON.parse('{"color":{"1":"red","2":"white","3":"blue"},"animal":{"1":"cat","2":"dog","3":"mouse"}}')
function toCSV(jsonObject) {
  var csv = [];
  for (var i in jsonObject) {
    if (jsonObject.hasOwnProperty(i)) {
      var title = i.indexOf(' ')>-1? '"'+i+'"': i;
      csv[0] ? csv[0].push(title) : csv[0] = [title];
      var k = Object.keys(jsonObject[i]);
      for (var j = 0; j < k.length; j++) {
        var val = jsonObject[i][k[j]].indexOf(' ')>-1? '"'+jsonObject[i][k[j]]+'"': jsonObject[i][k[j]];;
        csv[j+1] ? csv[j + 1].push(val) : csv[j+1] = [val];
      }
    }
  }
  return csv.join('\n');
}

document.body.innerHTML = toCSV(rep).replace(/\n/g, '<br>');

Upvotes: 1

Harpreet Singh
Harpreet Singh

Reputation: 2671

var k = JSON.parse('{"color":{"1":"red","2":"white","3":"blue"},"animal":{"1":"cat","2":"dog","3":"‌mouse"}, "price":{"1":"1000","2":"2000","3":"3000"}}');

var finalStr = '';
//Extract Top Columns Name
var keyList = [];
for(each in k) {
    keyList.push(each)
}
//Join them accordingly
finalStr = '"' + keyList.join(", ") + '"\n'

//As you said - Each of the inner objects always has the same number of elements (in this case, 3)
var startRef = k[keyList[0]];

//for each key in ref object
for(each in startRef) {
    var arr = [];
    //extract value for that key in each child object 
    for(var i=0;i<keyList.length;i++) {
        arr.push(k[keyList[i]][each])
    }
    //Join them accordingly
    finalStr += '"' + arr.join(", ") + '"\n'
}
console.log(finalStr)

//Output
"color, animal, price"
"red, cat, 1000"
"white, dog, 2000"
"blue, ‌mouse, 3000"

Upvotes: 1

Related Questions