Building Reusable Utility to Generate CSV in LWC

You will learn the following things

  1. How to Create a component
  2. How to Create reusable Utility
  3. How to convert data in proper format
  4. Fetch data from apex and generating the CSV file
  5. CSV file with custom header, file name and data

Video Tutorial


Code

  1. Create Lwc component csvDemo and add the following code to the respective files.
csvDemo.html
<template>
    <lightning-card title="CSV utility demo">
        <template for:each={userData} for:item="user">
            <div key={user.username}>
                <p>{user.username} {user.age}, {user.title}</p>
            </div>
        </template>

        <lightning-button variant="brand" label="download user data" onclick={downloadUserDetails}></lightning-button>

        <lightning-button variant="brand" label="download account data" onclick={downloadAccountData}></lightning-button>
    </lightning-card>
</template>
csvDemo.js
import { LightningElement, wire } from 'lwc';
import getAccounts from '@salesforce/apex/tableController.getAccounts'
import {exportCSVFile} from 'c/utils'
export default class CsvDemo extends LightningElement {
    accountData
    @wire(getAccounts)
    accountHandler({data}){
        if(data){
            console.log(data)
            this.accountData = data
        }
    }
    userData= [
        {
            username:"Nikhil",
            age:25,
            title:"Developer"
        },
        {
            username: 'Salesforcetroop',
            age: 2,
            title: 'Youtube channel'
        },
        {
            username: 'Friends',
            age: 20,
            title: 'Netflix series'
        }
    ]

    headers = {
        username:"User Name",
        age:"Age",
        title:"Title"
    }

    accountHeaders ={
        Id:"Record Id",
        Name:"Name",
        AnnualRevenue:"Annual Revenue",
        Industry:"Industry",
        Phone:"Phone"

    }
    downloadUserDetails(){
        console.log("download triggered.")
        exportCSVFile(this.headers, this.userData, "user detail")
    }
    downloadAccountData(){
        exportCSVFile(this.accountHeaders, this.accountData, "accounts detail")
    }
}
csvDemo.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>50.0</apiVersion>
    <isExposed>true</isExposed>
     <targets>
        <target>lightning__AppPage</target>
    </targets>
</LightningComponentBundle>
  1. Create Another Lwc component utils and convert it into the utility by deleting the html file from the component.
  2. Add the following code to the utils.js
utils.js
export function exportCSVFile(headers, totalData, fileTitle){
    if(!totalData || !totalData.length){
        return null
    }
    const jsonObject = JSON.stringify(totalData)
    const result = convertToCSV(jsonObject, headers)
    if(result === null) return
    const blob = new Blob([result])
    const exportedFilename = fileTitle ? fileTitle+'.csv' :'export.csv'
    if(navigator.msSaveBlob){
        navigator.msSaveBlob(blob, exportedFilename)
    } else if (navigator.userAgent.match(/iPhone|iPad|iPod/i)){
        const link = window.document.createElement('a')
        link.href='data:text/csv;charset=utf-8,' + encodeURI(result);
        link.target="_blank"
        link.download=exportedFilename
        link.click()
    } else {
        const link = document.createElement("a")
        if(link.download !== undefined){
            const url = URL.createObjectURL(blob)
            link.setAttribute("href", url)
            link.setAttribute("download", exportedFilename)
            link.style.visibility='hidden'
            document.body.appendChild(link)
            link.click()
            document.body.removeChild(link)
        }
    }
    

}
function convertToCSV(objArray, headers){
    const columnDelimiter = ','
    const lineDelimiter = '\r\n'
    const actualHeaderKey = Object.keys(headers)
    const headerToShow = Object.values(headers) 
    let str = ''
    str+=headerToShow.join(columnDelimiter) 
    str+=lineDelimiter
    const data = typeof objArray !=='object' ? JSON.parse(objArray):objArray

    data.forEach(obj=>{
        let line = ''
        actualHeaderKey.forEach(key=>{
            if(line !=''){
                line+=columnDelimiter
            }
            let strItem = obj[key]+''
            line+=strItem? strItem.replace(/,/g, ''):strItem
        })
        str+=line+lineDelimiter
    })
    console.log("str", str)
    return str
}
  1. Keep the code of utils.js-meta.xml as it is.
  2. Create an Apex class tableController.cls and add the following code to the file.
tableController.cls
public with sharing class tableController {
    @AuraEnabled(cacheable=true)
    public static List<Account> getAccounts() {
        return [SELECT Id, Name, AnnualRevenue, Industry, Phone from Account];
    }
}

Final Output

Now place your component to the record page. You will see the following output

on click of download user data local data gets downloaded and on click of download account data data from apex gets donwloaded

Fig:1 csvDemo component after pacing on the page
Fig:1 csvDemo component after pacing on the page


Site developed by Nikhil Karkra © 2021 | Icons made by Freepik