8

I know this is a question already answered but couldn't find the solution that works for me.

I've a HTML button that, when clicked, generate an array of objects in typescript(which basically javascript) and i want to generate a csv file that will be downloaded.

Here is the example of the javascript array of objects:

    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" }];

    // Loop the array of objects
for(let row = 0; row < items.length; row++){
    let keysAmount = Object.keys(items[row]).length
    let keysCounter = 0

    // If this is the first row, generate the headings
    if(row === 0){

       // Loop each property of the object
       for(let key in items[row]){

                           // This is to not add a comma at the last cell
                           // The '\n' adds a new line
           csv += key + (keysCounter+1 < keysAmount ? ',' : '\r\n' )
           keysCounter++
       }
    }else{
       for(let key in items[row]){
           csv += items[row][key] + (keysCounter+1 < keysAmount ? ',' : '\r\n' )
           keysCounter++
       }
    }

    keysCounter = 0
}
console.log(csv)

var hiddenElement = document.createElement('a');
        hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
        hiddenElement.target = '_blank';
        hiddenElement.download = 'people.csv';
        hiddenElement.click();

I tried this example code but in my case it create the csv file, but doesn't insert the csv string correctly in the csv file, the csv string is has rows of element separated by a comma and each row is determined by a new line, but here all the data of each row sits in one cell of the csv file, how can I make so that each value of each row sits in a different cell?

here is the csv string that it:

    name,color,size
Item 2,Green,X-Large
Item 3,Green,X-Large
5
  • 1
    this.ConvertToCSV(data) is a custom function that you made? Can you show us what it does? Commented Jun 6, 2017 at 18:11
  • 1
    what is ConvertToCSV? what does its output look like? Commented Jun 6, 2017 at 18:11
  • Also, If the problem is apparent in the console.log why not exclude the rest of the download code from the question? It seems irrelevant. Commented Jun 6, 2017 at 18:17
  • here is the function convertToCSV(data), i just added it, the function transform the array of object into a csv string Commented Jun 7, 2017 at 6:43
  • I updated the code and i'm making progress, but still i don't yet the result i want Commented Jun 7, 2017 at 9:49

2 Answers 2

9

CSV is just a file with each cell separated by a comma and each row separated by a new line. You want to name each column as the key of the object. If I understood correctly:

{ "name": "Item 1", "color": "Green", "size": "X-Large" }

Will be:

---------------------------
| name   | color |   size  |
---------------------------
| Item 1 | Green | X-Large |
---------------------------

UPDATE: This is the updated version.

So you can loop your array and generate the csv accordingly using the File API from HTML5:

let csv

// Loop the array of objects
for(let row = 0; row < items.length; row++){
    let keysAmount = Object.keys(items[row]).length
    let keysCounter = 0

    // If this is the first row, generate the headings
    if(row === 0){

       // Loop each property of the object
       for(let key in items[row]){

                           // This is to not add a comma at the last cell
                           // The '\r\n' adds a new line
           csv += key + (keysCounter+1 < keysAmount ? ',' : '\r\n' )
           keysCounter++
       }
    }else{
       for(let key in items[row]){
           csv += items[row][key] + (keysCounter+1 < keysAmount ? ',' : '\r\n' )
           keysCounter++
       }
    }

    keysCounter = 0
}

// Once we are done looping, download the .csv by creating a link
let link = document.createElement('a')
link.id = 'download-csv'
link.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(csv));
link.setAttribute('download', 'yourfiletextgoeshere.csv');
document.body.appendChild(link)
document.querySelector('#download-csv').click()

BTW If you are using TypeScript, then the last line document.querySelector('#download-csv').click() MUST be <HTMLElement>document.querySelector('#download-csv').click() Let me know if it worked for you.

Fiddle for TypeScript and javascript (it changes just the last line): https://jsfiddle.net/0p8revuh/4/

UPDATE: To see the file propertly formated in excel, a cell for each comma separated value, do the following:

  1. You will see your data in several rows. Just click on the 'A' column to select all the rows: enter image description here

  2. Go to your excel and click on Data at the top: enter image description here

  3. Click on Text to columns: enter image description here

  4. Select delimited: enter image description here

  5. Click on next and active comma: enter image description here

  6. Click on next and finish. Now you should be able to see your data propertly formated.

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

33 Comments

First thanks for your help, I tried the code and I get an error saying that "click doesn't exist on type element", the last line of code
can you execute document.querySelector("#download-csv") on chrome dev tools and see if you get the link?
yes it works and i get the link, that is what i get <a id="download-csv" download="MyReport.csv" href="#"></a>
Then you should be able to click it with document.querySelector("#download-csv").click() to get the download. It worked for me. Also try typeof document.querySelector('#download-csv')
It says it is an object
|
0

It works! But the way of code looks more complex and not easily understandable. I think the following code might be a little bit clear.

Also, I notified we need to keep the object key properly example if we want all in the capital we need to keep the object name in the capital but the property of the object key I'm not like to be capital. Most of the time It should be lowercase.In this case, also this solution might be helpful.

  let csvText = '';

    data.forEach((row, ind) => {
      if (!ind) {
        return (csvText += `${[
          'STOCK',
          'MAXPAIN',
          'CASH RATE',
          'FUTURE RATE',
          'PE',
          'PE OI',
          'CE',
          'CE OI',
          'PC RATIO MAX',
          'PC RATIO TOTAL'
        ].join(',')}\r\n`);
      }

      const properValues = [row.stock, row.option, row.strike, 0, row.put, row.put_oi, row.call, row.call_oi, 0, 0];

      return (csvText += `${properValues.join(',')}\r\n`);
    });

    console.log(csvText);

Ensure that heading value and not heading value return like the same order; otherwise, it'll be petrified.

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.