Generate a csv file from a javascript array of objects

20,346

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.

Share:
20,346
Freddy Sop
Author by

Freddy Sop

Updated on July 09, 2022

Comments

  • Freddy Sop
    Freddy Sop almost 2 years

    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
    
  • Freddy Sop
    Freddy Sop almost 7 years
    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
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    can you execute document.querySelector("#download-csv") on chrome dev tools and see if you get the link?
  • Freddy Sop
    Freddy Sop almost 7 years
    yes it works and i get the link, that is what i get <a id="download-csv" download="MyReport.csv" href="#"></a>
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    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')
  • Freddy Sop
    Freddy Sop almost 7 years
    It says it is an object
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    What browser are you using? It's working for me on google chrome. Btw are you using TypeScript?
  • Freddy Sop
    Freddy Sop almost 7 years
    i'm using Chrome too, and yeah i'm using typescript, is this the problem? because i thought that typescript is basically like javascript
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    Typescript is "typesafe" so the querySelector returns an HTMLElement which doesn't have the click() method. So you gotta convert it to an HTMLInputElement. Simple execute: (<HTMLInputElement>document.querySelector('#download-csv')).‌​click(). Let me know if it worked.
  • Freddy Sop
    Freddy Sop almost 7 years
    It says it cannot find the name click, but on chrome dev tools, i get the same link and of type object
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    Try to cast it to a HTMLScriptElement like: (<HTMLScriptElement>document.querySelector('#download-csv'))‌​.click()
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    Do it without the external parenthesis because it may think it's a function like this: <HTMLScriptElement>document.querySelector('#download-csv')​.‌​click()
  • Freddy Sop
    Freddy Sop almost 7 years
    It still says the same error, and i also have another question, not related to this one: before the for loop, you let a variable called mycsv but inside the loop you're using csv, i guess this is just an error or typing, and also once the csv string is created, how does the browser know that it should create a file that will contain the data of that csv string
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    You are correct that was a mistake by my part. Now I changed the variable name and set up the csv variable to download in the href with the new HTML5 syntax.
  • Freddy Sop
    Freddy Sop almost 7 years
    So please how does it look like now?
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    Ok finally got it working. You just need the <HTMLElement>. Check this 2 lines fiddle jsfiddle.net/k7uty4ss So basically do <HTMLElement>document.querySelector('#download-csv').click()
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    Btw I've updated the answer html to loop the file. Check it and let me know if it worked for you.
  • Freddy Sop
    Freddy Sop almost 7 years
    it says the property link doesn't exist on type element
  • Freddy Sop
    Freddy Sop almost 7 years
    I have updated my code but still get the same error for the link which says that the property link doesn't exist on type element
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    Check this fiddle jsfiddle.net/0p8revuh do you have the same code?
  • Freddy Sop
    Freddy Sop almost 7 years
    I have exactly the same code, but doesn't work on my side
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    In which line does the error appear? Can you try removing the last part that inserts the link and see if the error is coming from there? I've updated the code with the cast conversion in the last line for typescript. Check the 2 last lines from this fiddle: jsfiddle.net/0p8revuh/4
  • Freddy Sop
    Freddy Sop almost 7 years
    The error occurs only when i add .click() to the code
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    Can you show me your entire javascript code in a jsfiddle? That error is weird because there are no link properties on that element
  • Freddy Sop
    Freddy Sop almost 7 years
    var hiddenElement = document.createElement('a'); hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv); hiddenElement.target = '_blank'; hiddenElement.download = 'people.csv'; hiddenElement.click();
  • Freddy Sop
    Freddy Sop almost 7 years
    i tried this and i don't have any error, it creates and download the csv file , but just that each line of the csv string is contained in one cell in the csv file, it doesn't split the data of the line in different cells of that row
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    So it generates the csv file? Are you using excel to open it? The problems is that excel doesn't format the csv file automatically. You have to make some changes to separate each element by a comma. Take a look at my updated answer. I repeat. The problem is not in the code, it's the excel that doesn't know how to format Comma Separated Values. Take a look at my updated answer.
  • Freddy Sop
    Freddy Sop almost 7 years
    It worked, so it wasn't a problem of the code as i was thinking, instead the code was right, it was just a problem of excel
  • Merunas Grincalaitis
    Merunas Grincalaitis almost 7 years
    Yeah... Well it worked tho. Mark this as the valid answer if I helped you.
  • Syed Ayesha Bebe
    Syed Ayesha Bebe about 6 years
    This was fine it is creating two documents . But what we have to do when we want array of objects ? How can i use keys in csv?
  • Biswas Khayargoli
    Biswas Khayargoli over 5 years
    Guys, I think the first row or array[0] will ever be included in the csv file. First row will extract the headers but not the values. So first row values missing?
  • Uciebila
    Uciebila about 5 years
    This answer always misses one row, and the fix to get the data to present properly also does not work.
  • Supamic
    Supamic almost 3 years
    To Fix the missing first row, in the main for loop I started the row = -1 and then match that -1 to do the header row but you have to modify the Object.keys(items[0]).length to call the actual first item and in the header row loop each property of the first object, for(let key in items[0]). I also initialize the csv variable as an empty string to avoid an undefined in header on first pass.
  • xplorer1
    xplorer1 almost 3 years
    I ran into the missing first row problem. Couldn't fix it, so I looked for another solution and found this https://dev.to/samueldjones/convert-an-array-of-objects-to-c‌​sv-string-in-javascr‌​ipt-337d