How do I remove the extra comma in this CSV generator for loop

Viewed 114

I have a group of objects nested inside of an array.

I understand why the for loop is adding a comma at the end of the rows, but I'm having trouble finding out a better way to write this (brand-new to programming) which would not have the comma inside of the loop.

Is there a better way to write this?

function createCSV() {
    
    // CREATE THE CSV VARIABLE
    let csvContent = "data:text/csv;charset=utf-8,"
    let headers = "date,account,vendor,amount,recurring,description,notes"
    csvContent += headers + "\r\n"
    
    // ITERATE THE ARRAY INTO THE CSV SEPARATED BY COMMAS
    adjustments.forEach(element => {

        // EACH ARRAY ITEM
        let row
        
        //EACH OBJECT PROPERTY
        for (const property in element) {
            row += element[property]
            row += ','
          }

        csvContent += row + "\r\n";
    });

    // DOWNLOAD THE CSV
    var encodedUri = encodeURI(csvContent);
    var link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", "empower_data.csv");
    document.body.appendChild(link); // Required for FF
    link.click();
    console.log('CSV DOWNLOADED')
}
2 Answers

use array and array join

function createCSV() {
    let csvContent = "data:text/csv;charset=utf-8,";
    let headers = "date,account,vendor,amount,recurring,description,notes";
    csvContent += headers + "\r\n";

    adjustments.forEach(element => {
        // begin changes
        let row = [];
        for (const property in element) {
            row.push(element[property]);
        }
        csvContent += row.join(',') + "\r\n";
        // end changes
    });

    var encodedUri = encodeURI(csvContent);
    var link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", "empower_data.csv");
    document.body.appendChild(link);
    link.click();
    console.log('CSV DOWNLOADED');
}

better yet - replace all that with

function createCSV() {
    let csvContent = "data:text/csv;charset=utf-8,";
    let headers = "date,account,vendor,amount,recurring,description,notes";
    csvContent += headers + "\r\n";

    adjustments.forEach(element => {
        // begin changes
        csvContent += Object.values(element).join(',') + "\r\n";
        // end changes
    });

    var encodedUri = encodeURI(csvContent);
    var link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", "empower_data.csv");
    document.body.appendChild(link);
    link.click();
    console.log('CSV DOWNLOADED');
}

or for really neat code

function createCSV() {
    let csvContent = "data:text/csv;charset=utf-8,";
    let headers = "date,account,vendor,amount,recurring,description,notes";

    csvContent += headers + "\r\n";
    // begin changes
    csvContent += adjustments.map(
        element => Object.values(element).join(',')
    ).join('\r\n');
    // end changes
    var encodedUri = encodeURI(csvContent);
    var link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", "empower_data.csv");
    document.body.appendChild(link);
    link.click();
    console.log('CSV DOWNLOADED');
}

As a final note: since object properties don't have a defined "order" - you may want to do something like this

function createCSV() {
    const properties = ['date','account','vendor','amount','recurring','description','notes'];
    let csvContent = "data:text/csv;charset=utf-8,";
    let headers = "date,account,vendor,amount,recurring,description,notes";

    csvContent += headers + "\r\n";
    // begin changes
    csvContent += adjustments.map(element => properties.map(prop => element[prop]).join(',')).join('\r\n');
    // end changes
    var encodedUri = encodeURI(csvContent);
    var link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", "empower_data.csv");
    document.body.appendChild(link);
    link.click();
    console.log('CSV DOWNLOADED');
}

In the above, I assume the property names in the object are the same as the CSV column headers, but, of course, that's not necessarily the case (I simply don't know)

The best approach for that is to use array instead of string concatenation and finish this with array.join() :

function createCSV() {
    
    // CREATE THE CSV VARIABLE
    let csvContent = "data:text/csv;charset=utf-8,"
    let headers = "date,account,vendor,amount,recurring,description,notes"
    csvContent += headers + "\r\n"
    
    // ITERATE THE ARRAY INTO THE CSV SEPARATED BY COMMAS
    adjustments.forEach(element => {

        // EACH ARRAY ITEM
        const row = [];
        
        //EACH OBJECT PROPERTY
        for (const property in element) {
            row.push(element[property]);
        }

        csvContent += row.join(',') + "\r\n";
    });

    // DOWNLOAD THE CSV
    var encodedUri = encodeURI(csvContent);
    var link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", "empower_data.csv");
    document.body.appendChild(link); // Required for FF
    link.click();
    console.log('CSV DOWNLOADED')
}
Related