Thursday, May 30, 2019

Export data as CSV File with javascript in salesforce Lightning Web Component(lwc)

This post explains how to export data table data as a CSV file using javascript in salesforce Lightning web component(lwc).

I created a simple Lighting web component, this component is displayed Account data and one button to download CSV file.

Example:
exportDataToCSVInLWC.html
<template>
    <lightning-card title="Export Data as CSV in Lightning Web Components" icon-name="custom:custom63">
        <template if:true={data}>
            <div class="slds-p-around_medium lgc-bg-inverse">
                <p>Do you want download data as a CSV format, Click Here &nbsp;
                    <lightning-button icon-name="utility:download" 
                                      label="Download as CSV" 
                                      title="Download CSV File"
                                      onclick={downloadCSVFile} variant="brand"></lightning-button>
                </p>
            </div>
            <div class="slds-m-around_medium">
                <!-- Datatable component -->
                    <lightning-datatable columns={columns} 
                                         data={data} 
                                         hide-checkbox-column="true"
                                         key-field="id"></lightning-datatable>
            
            </div>
        </template>
    </lightning-card>
</template>

exportDataToCSVInLWC.js
import { LightningElement, track} from 'lwc';
// importing accounts
import getAccountList from '@salesforce/apex/LWCExampleController.getAccounts';
// imported to show toast messages
import {ShowToastEvent} from 'lightning/platformShowToastEvent';


// datatable columns
const cols = [
    {label: 'Name',fieldName: 'Name'}, 
    {label: 'Industry',fieldName: 'Industry'},
    {label: 'Type',fieldName: 'Type'}, 
    {label: 'Phone',fieldName: 'Phone',type: 'phone'}, 
    {label: 'Rating',fieldName: 'Rating'}, 
    {label: 'Account Number',fieldName: 'AccountNumber'}, 
];

export default class ExportDataToCSVInLWC extends LightningElement {
    @track error;
    @track data;
    @track columns = cols;

    // this constructor invoke when component is created.
    // once component is created it will fetch the accounts
    constructor() {
        super();
        this.getallaccounts();
    }

    // fetching accounts from server
    getallaccounts() {
        getAccountList()
        .then(result => {
            this.data = result;
            this.error = undefined;
        })
        .catch(error => {
            this.error = error;
            this.dispatchEvent(
                new ShowToastEvent({
                    title: 'Error while getting Accounts', 
                    message: error.message, 
                    variant: 'error'
                }),
            );
            this.data = undefined;
        });
    }

    // this method validates the data and creates the csv file to download
    downloadCSVFile() {   
        let rowEnd = '\n';
        let csvString = '';
        // this set elminates the duplicates if have any duplicate keys
        let rowData = new Set();

        // getting keys from data
        this.data.forEach(function (record) {
            Object.keys(record).forEach(function (key) {
                rowData.add(key);
            });
        });

        // Array.from() method returns an Array object from any object with a length property or an iterable object.
        rowData = Array.from(rowData);
        
        // splitting using ','
        csvString += rowData.join(',');
        csvString += rowEnd;

        // main for loop to get the data based on key value
        for(let i=0; i < this.data.length; i++){
            let colValue = 0;

            // validating keys in data
            for(let key in rowData) {
                if(rowData.hasOwnProperty(key)) {
                    // Key value 
                    // Ex: Id, Name
                    let rowKey = rowData[key];
                    // add , after every value except the first.
                    if(colValue > 0){
                        csvString += ',';
                    }
                    // If the column is undefined, it as blank in the CSV file.
                    let value = this.data[i][rowKey] === undefined ? '' : this.data[i][rowKey];
                    csvString += '"'+ value +'"';
                    colValue++;
                }
            }
            csvString += rowEnd;
        }

        // Creating anchor element to download
        let downloadElement = document.createElement('a');

        // This  encodeURI encodes special characters, except: , / ? : @ & = + $ # (Use encodeURIComponent() to encode these characters).
        downloadElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csvString);
        downloadElement.target = '_self';
        // CSV File Name
        downloadElement.download = 'Account Data.csv';
        // below statement is required if you are using firefox browser
        document.body.appendChild(downloadElement);
        // click() Javascript function to download CSV file
        downloadElement.click(); 
    }

}

exportDataToCSVInLWC.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="exportDataToCSVInLWC">
    <apiVersion>45.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

Apex Class
public inherited sharing class LWCExampleController {
    
    @AuraEnabled(Cacheable = true)
    public static List<Account> getAccounts(){
      return [SELECT Id, Name,Industry, Type, Phone, Rating, AccountNumber FROM Account ORDER BY Name LIMIT 10];
    }
}

Result:

18 comments:

  1. how to remove id field in csv file

    ReplyDelete
    Replies
    1. Remove the Id field in SOQL query.

      Delete
    2. You can also skip a column when you build your headers.

      FROM:

      // getting keys from data
      this.data.forEach(function (record) {
      Object.keys(record).forEach(function (key) {
      rowData.add(key);
      });
      });

      TO:
      // getting keys from data
      this.data.forEach(function (record) {
      Object.keys(record).forEach(function (key) {
      if(key !== 'Id) rowData.add(key);
      });
      });

      Delete
  2. How can I change the row header and the column order?

    ReplyDelete
  3. Is there a way to customize those fields? For example the length or the color of a specific field.

    ReplyDelete
  4. What is size limit for the CSV file and how many records does the download supports?

    ReplyDelete
    Replies
    1. Hi, where you able to find the Size and record limit?

      Delete
  5. not downloading the csv if am in lightning version. downloading file with "download" as name not as .csv extension. but this works in Classic version. any help?

    ReplyDelete
  6. Thank you for your post it has been very educational! I am using a lightning:tree-grid and would like to apply this logic to include an export to csv link. Unfortunately, I am fairly new to Salesforce and am not sure how to break out the child row object(s). Can you suggest what I might do to modify your solution for a tree-grid? Thank you for your time and assistance!

    ReplyDelete
  7. Hi All,

    Can you please post same functionality in Aura component.

    ReplyDelete
  8. Export data is not working in salesforce mobile app.

    ReplyDelete
  9. @Mohinish, how did you overcome download file name issue?

    ReplyDelete
  10. Hey there, would it be possible for you to show how to do the same thing but export as an Excel file (.xls) rather than .CSV?

    ReplyDelete
  11. How to export lineItem data in parent ID

    ReplyDelete
  12. When I choose a custom object I'm getting custom api names of respective fields in csv , but I should get label names can anyone ols let me know how to do it

    ReplyDelete
  13. Hi,
    Thanks for the example ,
    and it works pretty good.
    One issue which I am having.
    If I have a lot of data it cuts my csv file.
    Is there any workarounds for this.

    ReplyDelete
    Replies
    1. I am facing the same situation. Did you find out the answer?

      Delete
  14. Thank-you very much, this was really helpful!!!

    ReplyDelete