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:

Tuesday, May 28, 2019

How to check custom metadata type usage in salesforce

From Summer 19 onwards we can view custom metadata type usage in System overview.
Path:
From Setup, enter System Overview in the Quick Find box, and then select System Overview.


Monday, May 27, 2019

How to call Lightning Web components from Visualforce page

This post explains how to call Lightning web components from the visualforce page.

From Summer 19 onwards we can use Lightning web component in the visualforce page,
normally to call lightning components in the visualforce page we used  $A.createComponent and $Lightning.use.
we can use the same concept as well in lightning web components.

Note: To work this functionality, API version should be above or equal to v46


Demo:

lwcInVisualforceDemo.html
<template>
    <lightning-card title="Calling Lightning Web Components From Visualforce Page" icon-name="standard:account">
        <template if:true={accData}>
            <table class="slds-table slds-table_bordered slds-table_cell-buffer slds-table_col-bordered">
                <thead>
                    <tr class="slds-text-title_caps">
                        <th scope="col">
                            <div title="Key">Account Name</div>
                        </th>
                        <th scope="col">
                            <div title="Value">Industry</div>
                        </th>
                    </tr>
                </thead>
                <tbody>
                    <template for:each={accData} for:item="acc">
                        <tr key={acc.key}>
                            <th scope="col">
                                <div>{acc.Name}</div>
                            </th>
                            <th scope="col">
                                <div>{acc.Industry}</div>
                            </th>
                        </tr>
                    </template>
                </tbody>
            </table>
        </template>
    </lightning-card>
</template>

lwcInVisualforceDemo.js
import { LightningElement, track, wire } from 'lwc';
// importing apex class and method to retrive accounts
import retriveAccounts  from '@salesforce/apex/LWCExampleController.fetchAccounts';

export default class LwcInVisualforceDemo extends LightningElement {

    // to track object name from vf page
    @track objName = 'Account';
    @track accData;
    @track error;

    // getting accounts using wire service
    @wire(retriveAccounts, {strObjectName : '$objName'})
    accounts({data, error}) {
        if(data) {
            this.accData = data;
            this.error = undefined;
        }
        else if(error) {
            this.accData = undefined;
            this.error = error;
            window.console.log(error);
        }
    }
}

LWCExampleController.cls
public inherited sharing class LWCExampleController {
    @AuraEnabled(Cacheable = true)
    public static list<Account> fetchAccounts(String strObjectName) {
        if(String.isNotBlank(strObjectName)) {
            return Database.query('SELECT Id, Name, Industry From ' + strObjectName + ' limit 10');
        }
        else {
            return null;
        }
    }
}
Create lightning out dependency Lightning application, and Visualforce page to call lwc component.

CallingLWCFromPage.page
<apex:page>
    <apex:includeLightning />
    <div id="lwcDemo" />
    <script>
    $Lightning.use("c:lwcInVisualforceApp", function() {
        $Lightning.createComponent("c:lwcInVisualforceDemo", {
            //pass parameter values to lwc js controller
            objName : "Account" // optional parameter, I already declared value in lwc js controller.
        },
        "lwcDemo",
            function(component) {
             console.log("Lightning Web Component created Successfully!!");
              // extend the functionality as per your requirement
            }
       );
    });
    </script>
</apex:page>

lwcInVisualforceApp.app
<aura:application  access="GLOBAL" extends="ltng:outApp" >
 <aura:dependency resource="lwcInVisualforceDemo"/>
</aura:application>

Result:

Resource:
https://releasenotes.docs.salesforce.com/en-us/summer19/release-notes/rn_lwc_vf.htm?edition=&impact=

Saturday, May 25, 2019

Components names for ANT tool

Package.xml file for retrieving the Salesforce components in ANT tool

Last updated on 05/May/2020


package.xml
<?xml encoding="UTF-8" version="1.0"?>
<Package
    xmlns="http://soap.sforce.com/2006/04/metadata">
    <!-- Custom Object Tab, Web Tab and Visualforce tab -->
    <types>
        <members>Employee__c</members>
        <name>CustomTab</name>
    </types>

    <types>
        <members>*</members>
        <name>ApexClass</name>
    </types>

    <types>
        <members>*</members>
        <name>ApexComponent</name>
    </types>

    <types>
        <members>*</members>
        <name>ApexPage</name>
    </types>

    <types>
        <members>*</members>
        <name>ApexTrigger</name>
    </types>
 
 <!-- Sharing Rules -->
 
 <types>
  <members>Account.*</members>
  <name>SharingCriteriaRule</name>
 </types>

 <types>
  <members>Account.*</members>
  <name>SharingOwnerRule</name>
 </types>

    <!-- For retrieving Lightning components -->
    <types>
        <members>*</members>
        <name>AuraDefinitionBundle</name>
    </types>
 
 <!-- For retrieving Lightning web components -->
 <types>
  <members>*</members>
  <name>LightningComponentBundle</name>
 </types>

    <!-- for retrieving Layouts -->
    <types>
        <members>Account-Personal Account Layout</members>
        <members>MyCustomObject__c-My CustomObject Layout</members>
        <name>Layout</name>
    </types>

    <types>
        <members>*</members>
        <name>CustomApplication</name>
    </types>

    <types>
        <members>Activity.Closed__c</members>
        <name>CustomField</name>
    </types>

    <!-- For retrieving Custom Object, Custom Setting, Custom Metadata types-->
    <types>
        <members>*</members>
        <members>Account</members>
        <name>CustomObject</name>
    </types>


    <!-- Custom Tab -->
    <types>
        <members>*</members>
        <name>CustomTab</name>
    </types>

    <!-- Document -->
    <types>
        <members>Images/profilepic.png</members>
        <name>Document</name>
    </types>

    <!-- StandardValueSet, Standard Picklist values -->
    <types>
        <members>CasePriority</members>
        <members>CaseReason</members>
        <members>Industry</members>
        <members>LeadSource</members>
        <name>StandardValueSet</name>
    </types>

    <!-- Remote Site Setting -->
    <types>
        <members>Name1</members>
        <members>Name2</members>
        <name>RemoteSiteSetting</name>
    </types>

    <!-- Sharing Set  -->
    <types>
        <members>Name2</members>
        <members>Name1</members>
        <name>SharingSet</name>
    </types>

    <!-- Data Category Group -->
    <types>
        <members>Name2</members>
        <members>Name1</members>
        <name>DataCategoryGroup</name>
    </types>

    <!-- CustomSite -->
    <types>
        <members>Name2</members>
        <members>Name1</members>
        <name>CustomSite</name>
    </types>

    <!-- Approval Process -->
    <types>
        <members>ObjectName.ApprovalProcessName</members>
        <name>ApprovalProcess</name>
    </types>

    <!-- Entitlement Process -->
    <types>
        <members>EntitlementProcessName_(v)versionnumber</members>
        <name>EntitlementProcess</name>
    </types>
    <!-- For retrieving and deploying Email Templates, folder name is mandatory  -->
    <types>
        <members>unfiled$public/Test_Notification</members>
        <members>EmailTemplates/InquiryPortal</members>
        <name>EmailTemplate</name>
    </types>

    <types>
        <members>*</members>
        <name>HomePageComponent</name>
    </types>

    <types>
        <members>*</members>
        <name>HomePageLayout</name>
    </types>

    <!-- Home Page Custom Link -->
    <types>
        <members>*</members>
        <name>CustomPageWebLink</name>
    </types>


    <types>
        <members>Account.My_Account_Team</members>
        <name>ListView</name>
    </types>

    <types>
        <members>Account-Account Layout</members>
        <name>Layout</name>
    </types>

    <types>
        <members>Analyst</members>
        <name>Profile</name>
    </types>


    <types>
        <!--Report Folder-->
        <members>ExtraReports</members>
        <!--Report-->
        <members>ExtraReports/AnyOccupation</members>
        <!--Report from Unfiled Public Reports-->
        <members>unfiled$public/Test</members>
        <name>Report</name>
    </types>

    <types>
        <!--Dashboard Folder-->
        <members>ExtraDashboards</members>
        <!--Dashboard-->
        <members>ExtraDashboards/AnyOccupation</members>
        <name>Dashboard</name>
    </types>

    <types>
        <members>*</members>
        <name>ReportType</name>
    </types>

    <types>
        <members>*</members>
        <name>StaticResource</name>
    </types>

    <types>
        <members>Contact.SelectTitle</members>
        <name>WebLink</name>
    </types>

    <types>
        <members>*</members>
        <name>PermissionSet</name>
    </types>

    <types>
        <members>*</members>
        <name>QuickAction</name>
    </types>


    <!-- Workflow includes WorkflowFieldUpdate, WorkflowAlert, WorkflowOutboundMessage, WorkflowRule -->
    <types>
        <members>ObjectName.WorkFlowName</members>
        <name>Workflow</name>
    </types>


    <types>
        <members>ObjectName.FieldUpdateName</members>
        <name>WorkflowFieldUpdate</name>
    </types>

    <types>
        <members>ObjectName.FieldUpdateName</members>
        <name>WorkflowAlert</name>
    </types>

    <types>
        <members>ObjectName.FieldUpdateName</members>
        <name>WorkflowOutboundMessage</members>
    </types>

    <types>
        <members>ObjectName.FieldUpdateName</members>
        <name>WorkflowRule</name>
    </types>

    <types>
        <members>ObjectName.FieldUpdateName</members>
        <name>WorkflowTask</name>
    </types>


    <!--  Custom Button/Link -->
    <types>
        <members>Directory_Edition__c.Final_Letter_Renewal</members>
        <name>WebLink</name>
    </types>

    <!--  Standard Tabs and Fields renames -->
    <types>
        <members>*</members>
        <name>CustomObjectTranslation</name>
    </types>

    <!-- Validation Rules  -->
    <types>
        <members>Object Name.Validation Name</members>
        <name>ValidationRule</name>
    </types>

    <!--  Record Types  -->
    <types>
        <members>Object Name.Record Type Name</members>
        <name>RecordType</name>
    </types>

    <!--  Role  -->
    <types>
        <members>*</members>
        <name>Role</name>
    </types>

    <!--  Queue -->
    <types>
        <members>*</members>
        <name>Queue</name>
    </types>


    <!-- Public Group -->
    <types>
        <members>*</members>
        <name>Group</name>
    </types>

    <!-- Custom Labels -->
    <types>
        <members>*</members>
        <name>CustomLabel</name>
    </types>

    <!-- LetterHead -->
    <types>
        <members>*</members>
        <name>Letterhead</name>
    </types>

    <!-- Process Builder and Flow -->
    <types>
        <members>*</members>
        <name>Flow</name>
    </types>

    <types>
        <members>LogACall</members>
        <!--Global Action -->
        <members>Task.TestingAction</members>
        <!--Object Quick Action -->
        <name>QuickAction</name>
    </types>

    <version>48.0</version>
</Package>

Saturday, May 18, 2019

Callback Methods in Lightning Web Components(lwc)

Callback methods are triggered at a specific phase of a component instance lifecycle.

Callback Methods in Lighting Web Components(lwc)

1. constructor()
2. connectedCallback()
3. disconnectedCallback()
4. render()
5. renderedCallback()
6. errorCallback(error, stack)


constructor()

  • This callback method called when the component created.
  • This method lifecycle flows from Parent to Child component.
  • You can access the host element with this.template.
  • we can’t access child elements in the component body because they don’t exist yet.

connectedCallback()

  • This callback method called when the element is inserted into a document.
  • This method lifecycle flows from Parent to Child Component.
  • we can’t access child elements in the component body because they don’t exist yet.
  • You can access the host element with this.template.

disconnectedCallback()

  • This callback method called when the element is removed from a document.
  • This method lifecycle flows from Parent to Child Component.

render()

  • This callback method used to conditionally rendering a template or importing a custom one, use render() to override standard rendering functionality. 
  • This function gets invoked after connectedCallback() and must return a valid HTML template.

renderedCallback()

  • This Method called after every render of the component.
  • This callback method is specific to Lightning Web Components, it isn’t from the HTML custom elements specification.
  • This method flows from child to parent.

 errorCallback(error, stack)

  • This method called when a descendant component throws an error in one of its callback.
  •  The error argument is a JavaScript native error object, and the stack argument is a string.
  •  This callback method is specific to Lightning Web Components, it isn’t from the HTML custom elements specification.

Wednesday, May 15, 2019

System Mode and User Mode in Salesforce


System Mode:

1.  System mode running apex code by ignoring user’s permissions.
2.  In system mode, Apex code has access to all objects and fields permissions, field-level security,      sharing rules aren’t applied for the current user. 

User Mode:

1. User mode running apex code by respecting user’s permissions and sharing of records.
2. Profile level permissions, field-level security, and sharing rules are applied for the current user.

Modes Of Execution in Salesforce

 Apex Class     System Mode
Triggers1. If triggers call an apex class with sharing keyword, Then record level access permissions will be considered.
Anonymous Apex     User Mode
Apex Webservices (SOAP API and REST API)    System Mode
Validation Rule    System Mode
Workflow Rule    System Mode
Process Builder    System Mode
Formula Fields    System Mode
Custom Button    System Mode
Roll Up Summary Fileds     System Mode
Auto Response Rule    System Mode
Assignment Rule    System Mode
Escalation Rule    System Mode
Approval Process    System Mode
FlowsBy Default runs in User Mode
1. if flow called from Process Builder it runs in System      Mode.
2. if flow called from Workflow it runs in System              Mode.
3. if flow called from Apex it runs depends on With or With Out Sharing of apex class


Test Class1. Test Method with System.runAs() runs in User Mode.
2. Test Method without System.runAs() runs                  in System Mode.
All Type of Jobs   System Mode
Email Service   User Mode
Visualforce PageStandard Controller --- User Mode
Standard Controller With Extensions --- System Mode
Custom Controller---- Based Sharing Keyword Used in Apex Class.

Visualforce ComponentIt depends on the Visualforce page where it is used.
Chatter in Apex User Mode
Macros System Mode
InvocableMethod1. if it is called from Flow it will run in User Mode.
2. if it is called from Process Builder (does it depends on with or without sharing is specified on that Class), then runs in System Mode
Publisher Action System Mode
Custom Button System Mode


Saturday, May 4, 2019

How to iterate map of list values in Lightning web components(lwc)

This post explains how to iterate map of list values in Lightning web components(lwc)

Demo:

Apex Class:
public inherited sharing class LWCExampleController {
    @AuraEnabled(cacheable=true)    
    public static map<String, list<String>> returnMapOfListValues() {
        map<String, list<String>> mapOfListValues = new map<String, list<String>>();
        
        mapOfListValues.put('India', new list<String>{'Hyderabad', 'Delhi', 'Mumbaie'});
        mapOfListValues.put('USA', new list<String>{'New York', 'Las Vegas', 'Miami'});
        mapOfListValues.put('China', new list<String>{'Shenzhen', 'Guangzhou', 'Shanghai'});
        return mapOfListValues;
    }
}


showMapOfListValuesDemo.html
<template>
    <lightning-card title="Iterate Map Values Demo">
        <template if:true={mapOfListValues}>
            <table class="slds-table slds-table_bordered slds-table_cell-buffer slds-table_col-bordered">
                <thead>
                    <tr class="slds-text-title_caps">
                        <th scope="col">
                            <div title="Key">Country Name (Key)</div>
                        </th>
                        <th scope="col">
                            <div title="Value">Popular City Names (List Values)</div>
                        </th>
                    </tr>
                </thead>
                <tbody>
                    <template for:each={mapOfListValues} for:item="keyValue">
                        <tr key={keyValue.key}>
                            <th scope="col">
                                <div>{keyValue.key}</div>
                            </th>
                            <template for:each={keyValue.value} for:item="value">
                                <div key={value}>
                                    <b>{value}</b><br/>
                                </div>
                            </template>
                        </tr>
                    </template>
                </tbody>
            </table>
        </template>
    </lightning-card>
</template>

showMapOfListValuesDemo.js
import { LightningElement, track, wire } from 'lwc';
import getMapOfData from '@salesforce/apex/LWCExampleController.returnMapOfListValues';

export default class ShowMapOfListValuesDemo extends LightningElement {
    @track mapOfListValues = [];

    @wire(getMapOfData)
    mapOfData({data, error}) {
        if(data) {
            for(let key in data) {
                // Preventing unexcepted data
                if (data.hasOwnProperty(key)) { // Filtering the data in the loop
                    this.mapOfListValues.push({key: key, value: data[key]});
                }
            }
        }
        else if(error) {
            window.console.log(error);
        }
    }
}

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

Result: