Tag: Apex

Call Apex Methods In Lightning web components

Let’s discuss here how to call the apex class from the Lightning web components. Lightning web components can import methods from Apex classes into the JavaScript classes using ES6 import. Once after importing the apex class method you can able call the apex methods as functions into the component by calling either via the wire service or imperatively. Before you use an Apex method, make sure that there isn’t an easier way to get the data. See whether a base Lightning component, like lightning-record-form, lightning-record-view-form, or lightning-record-edit-form works for your use case. If they don’t give you enough flexibility, use a wire adapter like getListUi or getRecordUi. 

Refer this link for how to configure the Salesforce dx for web components 

Import Syntax 

You can able use default export syntax to import an Apex method via the @salesforce/apex scoped module into JavaScript controller class. The Syntax looks like below.

import apexMethod from '@salesforce/apex/Namespace.Classname.apexMethod';

apexMethod—The imported symbol that identifies the Apex method.
Namespace—The namespace of the Salesforce organization. Specify a namespace unless the organization uses the default namespace (c), in which case don’t specify it.
Classname—The name of the Apex class.

Create Apex Class 

In this example, we will be getting account data and show it into the UI. Create an apex class using SFDX create apex class command.

sfdx force:apex:class:create -n GetAccountData -d force-app/main/default/apex

Here is the apex class. To expose an Apex method to a Lightning web component, the method must be static and either global or public. Annotate the method with @AuraEnabled

public with sharing class GetAccountData {
   @AuraEnabled(cacheable=true)
    public static List<Account> getAccountList() {
        return [SELECT Id, Name,Type,Rating,Phone FROM Account];
    }
}

Now you can able to call the apex class in  Lightning web component using these different ways.

  • Wire a property
  • Wire a function
  • Call a method imperatively

Wire an Apex Method to a Property

If an Apex method is annotated with @AuraEnabled(Cacheable=true), you can invoke it from a component via the wire service. You can @wire a property or a function. Here is the syntax

import apexMethod from '@salesforce/apex/Namespace.Classname.apexMethod';
@wire(apexMethod, { apexMethodParams })
propertyOrFunction;

Create a Lightning web component using below SFDX commands

sfdx force:lightning:component:create --type lwc -n LWCWireEx -d force-app/main/default/lwc

Here is the LWCWireEx.html markup for the lightning web components.

<template>
    <lightning-card title="Apex Class Example" icon-name="custom:custom63">
            <div class="slds-m-around_medium">
                <template if:true={accounts.data}>
                    <template for:each={accounts.data} for:item="acc">
                        <p key={acc.Id}>{acc.Name}</p>
                    </template>
                </template>
                
            </div>
        </lightning-card>
</template>

Here is the LWCWireEx.js class

import { LightningElement, wire } from 'lwc';
import getAccountList from '@salesforce/apex/GetAccountData.getAccountList';

export default class LWCWireEx extends LightningElement {
    @wire(getAccountList) accounts;
}

Here is the LWCWireEx.js-meta.xml markup.

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>45.0</apiVersion>
    <isExposed>false</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
       </targets>
</LightningComponentBundle>

Push the changes to scratch org and add the lightning web component to the record page. You can able to see the result like below.

Wire an Apex Method to a Function

Now let’s look at how to wire an apex method to function.we will be updating the same code here to operate the apex method as function.

Update the LWCWireEx.js class as shown below

import { LightningElement, wire,track } from 'lwc';
import getAccountList from '@salesforce/apex/GetAccountData.getAccountList';

export default class LWCWireEx extends LightningElement {
    @track accounts;
    @track error;
    @wire(getAccountList)
    wiredAccounts({ error, data }) {
        if (data) {
            this.accounts = data;
        } else if (error) {
            console.log(error);
            this.error = error;
        }
    }
}

update the LWCWireEx.html markup as shown below

<template>

    <lightning-card title="Apex Wire To Function Example" icon-name="custom:custom63">

        <div class="slds-m-around_medium">
            <template if:true={accounts}>
                 <ul>
                <template for:each={accounts} for:item="account">
                    <li key={account.Id}> {account.Name} </li>
                </template>
             </ul>
            </template>
            <template if:true={error}>
                {error}
            </template>                
        </div>
    </lightning-card>
</template>

Push the changes to scratch org and add the lightning web component to the record page. You can able to see the result like below.

 

Call an Apex Method Imperatively

Now let’s see here how to call apex method imperatively. Create a new Lightning web component using the below SFDX command

sfdx force:lightning:component:create --type lwc -n ImperativEx -d force-app/main/default/lwc

Use the below ImperativEx.html code

<template>
        <lightning-card title="Apex Imperative Method Example">
            <div class="slds-m-around_medium">
                <p class="slds-m-bottom_small">
                    <lightning-button label="Load Accounts" onclick={handleLoad}></lightning-button>
                </p>
                <template if:true={accounts}>
                    <template for:each={accounts} for:item="account">
                        <p key={account.Id}>{account.Name}</p>
                    </template>
                </template>
                <template if:true={error}>
                   {error}
                </template>
            </div>
        </lightning-card>
    </template>

Use the below ImperativEx.js class code

import { LightningElement, wire,track } from 'lwc';
import getAccountList from '@salesforce/apex/GetAccountData.getAccountList';


export default class ImperativEx extends LightningElement {
    @track accounts;
    @track error;
    handleLoad() {
        getAccountList()
            .then(result => {
                this.accounts = result;
            })
            .catch(error => {
                this.error = error;
            });
    }
}


Use the below ImperativEx.js-meta.xml class code

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="hello">
    <apiVersion>45.0</apiVersion>
    <isExposed>false</isExposed>
     <targets>
        <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

push the changes to scratch org and add the lightning web component to the record page and you can able to see the below result when you click on the button .

Calling Apex Methods In Lightning web components

Let’s discuss here how to call the apex class from the Lightning web components. Lightning web components can import methods from Apex classes into the JavaScript classes using ES6 import. Once after importing the apex class method you can able call the apex methods as functions into the component by calling either via the wire service or imperatively. Before you use an Apex method, make sure that there isn’t an easier way to get the data. See whether a base Lightning component, like lightning-record-form, lightning-record-view-form, or lightning-record-edit-form works for your use case. If they don’t give you enough flexibility, use a wire adapter like getListUi or getRecordUi. 

Refer this link for how to configure the Salesforce dx for web components 

Import Syntax 

You can able use default export syntax to import an Apex method via the @salesforce/apex scoped module into JavaScript controller class. The Syntax looks like below.

import apexMethod from '@salesforce/apex/Namespace.Classname.apexMethod';

apexMethod—The imported symbol that identifies the Apex method.
Namespace—The namespace of the Salesforce organization. Specify a namespace unless the organization uses the default namespace (c), in which case don’t specify it.
Classname—The name of the Apex class.

Create Apex Class 

In this example, we will be getting account data and show it into the UI. Create an apex class using SFDX create apex class command.

sfdx force:apex:class:create -n GetAccountData -d force-app/main/default/apex

Here is the apex class. To expose an Apex method to a Lightning web component, the method must be static and either global or public. Annotate the method with @AuraEnabled

public with sharing class GetAccountData {
   @AuraEnabled(cacheable=true)
    public static List<Account> getAccountList() {
        return [SELECT Id, Name,Type,Rating,Phone FROM Account];
    }
}

Now you can able to call the apex class in  Lightning web component using these different ways.

  • Wire a property
  • Wire a function
  • Call a method imperatively

Wire an Apex Method to a Property

If an Apex method is annotated with @AuraEnabled(Cacheable=true), you can invoke it from a component via the wire service. You can @wire a property or a function. Here is the syntax

import apexMethod from '@salesforce/apex/Namespace.Classname.apexMethod';
@wire(apexMethod, { apexMethodParams })
propertyOrFunction;

Create a Lightning web component using below SFDX commands

sfdx force:lightning:component:create --type lwc -n LWCWireEx -d force-app/main/default/lwc

Here is the LWCWireEx.html markup for the lightning web components.

<template>
    <lightning-card title="Apex Class Example" icon-name="custom:custom63">
            <div class="slds-m-around_medium">
                <template if:true={accounts.data}>
                    <template for:each={accounts.data} for:item="acc">
                        <p key={acc.Id}>{acc.Name}</p>
                    </template>
                </template>
                
            </div>
        </lightning-card>
</template>

Here is the LWCWireEx.js class

import { LightningElement, wire } from 'lwc';
import getAccountList from '@salesforce/apex/GetAccountData.getAccountList';

export default class LWCWireEx extends LightningElement {
    @wire(getAccountList) accounts;
}

Here is the LWCWireEx.js-meta.xml markup.

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>45.0</apiVersion>
    <isExposed>false</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
       </targets>
</LightningComponentBundle>

Push the changes to scratch org and add the lightning web component to the record page. You can able to see the result like below.

Wire an Apex Method to a Function

Now let’s look at how to wire an apex method to function.we will be updating the same code here to operate the apex method as function.

Update the LWCWireEx.js class as shown below

import { LightningElement, wire,track } from 'lwc';
import getAccountList from '@salesforce/apex/GetAccountData.getAccountList';

export default class LWCWireEx extends LightningElement {
    @track accounts;
    @track error;
    @wire(getAccountList)
    wiredAccounts({ error, data }) {
        if (data) {
            this.accounts = data;
        } else if (error) {
            console.log(error);
            this.error = error;
        }
    }
}

update the LWCWireEx.html markup as shown below

<template>

    <lightning-card title="Apex Wire To Function Example" icon-name="custom:custom63">

        <div class="slds-m-around_medium">
            <template if:true={accounts}>
                 <ul>
                <template for:each={accounts} for:item="account">
                    <li key={account.Id}> {account.Name} </li>
                </template>
             </ul>
            </template>
            <template if:true={error}>
                {error}
            </template>                
        </div>
    </lightning-card>
</template>

Push the changes to scratch org and add the lightning web component to the record page. You can able to see the result like below.

 

Call an Apex Method Imperatively

Now let’s see here how to call apex method imperatively. Create a new Lightning web component using the below SFDX command

sfdx force:lightning:component:create --type lwc -n ImperativEx -d force-app/main/default/lwc

Use the below ImperativEx.html code

<template>
        <lightning-card title="Apex Imperative Method Example">
            <div class="slds-m-around_medium">
                <p class="slds-m-bottom_small">
                    <lightning-button label="Load Accounts" onclick={handleLoad}></lightning-button>
                </p>
                <template if:true={accounts}>
                    <template for:each={accounts} for:item="account">
                        <p key={account.Id}>{account.Name}</p>
                    </template>
                </template>
                <template if:true={error}>
                   {error}
                </template>
            </div>
        </lightning-card>
    </template>

Use the below ImperativEx.js class code

import { LightningElement, wire,track } from 'lwc';
import getAccountList from '@salesforce/apex/GetAccountData.getAccountList';


export default class ImperativEx extends LightningElement {
    @track accounts;
    @track error;
    handleLoad() {
        getAccountList()
            .then(result => {
                this.accounts = result;
            })
            .catch(error => {
                this.error = error;
            });
    }
}


Use the below ImperativEx.js-meta.xml class code

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="hello">
    <apiVersion>45.0</apiVersion>
    <isExposed>false</isExposed>
     <targets>
        <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

push the changes to scratch org and add the lightning web component to the record page and you can able to see the below result when you click on the button .

Lightning Web Components Render List

One of the most common use cases is to iterate through the collection when you are working on data collection. Let’s discuss here what all the different ways to do it in lightning web components. To render a list of items, use for each directive or the iterator directive to iterate over an array. Add the directive to a nested <template> tag that encloses the HTML elements you want to repeat. Please refer this link for web component environment setup

Using for:each directive

Let us discuss here how to use the for:each. When using the for:each directive, use for:item=”currentItem” to access the current item. To assign a key to the first element in the nested template, use the key={uniqueId} directive. Regardless of which directive you use, you must use a key directive to assign a unique ID to each item. When a list changes, the framework uses the key to rerender only the item that changed. The key must be a string or a number, it can’t be an object. You can’t use the index as a value for the key. Assign unique keys to an incoming data set. Here is the simple apex class that will get the data from the account object and its contacts. create an apex class using the below  SFDX command.

sfdx force:apex:class:create -n AccountContactController 

Here is the complete code.

public with sharing class AccountContactController {
     
    @AuraEnabled(cacheable=true)
    public static List<Account> getAccountContactList() {
        return [SELECT Id, Name,(Select Id,Name from Contacts) FROM Account];
    }

}

Below is the lightning web component that will iterate over an array called accounts, which is defined in the component’s JavaScript class.  Run the following SFDX command to create a web component

sfdx force:lightning:component:create --type lwc -n CollectionExample

CollectionExample.html

<template>
    <lightning-card title="Account Collection" icon-name="custom:custom14">
        <ul class="slds-list_ordered">
            <template for:each={accounts.data} for:item="account">
                <li key={account.Id}>
                    {account.Name}
                </li>
            </template>
        </ul>
    </lightning-card>
</template>

the above markup is iterating the data using the for:each directive as like below.

 <template for:each={accounts.data} for:item="account">

CollectionExample.js

import { LightningElement, track, wire } from 'lwc';

import getAccountContactList from '@salesforce/apex/AccountContactController.getAccountContactList';

export default class CollectionExample extends LightningElement {
    @wire(getAccountContactList) accounts; 
}

CollectionExample.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>45.0</apiVersion>
    <isExposed>false</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

Now push the component changes to scratch org and add this component to the record page. You can able to see the collection iteration data as shown below.

 

Nested Iteration using for:each directive

Now let us iterate the nested loop using the for:each directive .here is the example that will render the account and its contacts. Update the CollectionExample.html markup with the below code and push the changes to scratch org.

<template>
<lightning-card title="Account Collection" icon-name="custom:custom14">
<ul class="slds-list_ordered">
    <template for:each={accounts.data} for:item="account">
        <li key={account.Id}>
            {account.Name}
            <ul class="slds-list_ordered">
            <template for:each={account.Contacts} for:item="contact">
                    <li key={contact.Id}>{contact.Name}
                </li>
            </template>
        </ul>
        </li>
    </template>
</ul>
</lightning-card>
</template>

Push the change to scratch org and reload the page. Here is the final output.

 

Using Iterator directive

Iterator directive is another way to render the collection data. To apply a special behavior to the first or last item in a list, use the iterator directive, iterator:iteratorName={array}. Use iteratorName to access these properties:

  1. value—The value of the item in the list. Use this property to access the properties of the array. For example, iteratorName.value.propertyName.
  2. index—The index of the item in the list.
  3. first—A boolean value indicating whether this item is the first item in the list.
  4. last—A boolean value indicating whether this item is the last item in the list.

This sample code uses the same array as the previous example. To apply special rendering to the first and last items in the list, the code uses the first and last properties with the if:true directive. Update the  CollectionExample.html code with below code . in this example we will be displaying the list of accounts.

<template>
        <lightning-card title="Apex Iterator Example" icon-name="custom:custom14">
            <ul class="slds-m-around_medium">
                <template iterator:it={accounts.data}>
                    <li key={it.value.Id}>
                        <div if:true={it.first} class="list-first"></div>
                        {it.value.Name}
                        <div if:true={it.last} class="list-last"></div>
                    </li>
                </template>
            </ul>
        </lightning-card>
    </template>

CollectionExample.css 

.list-first {
    border-top: 1px solid black;
    padding-top: 5px;
}

.list-last {
    border-bottom: 1px solid black;
    padding-bottom: 5px;
}

Push the changes to scratch org and you can able to see these changes after reload.

Now let us see how to do the nested iteration using iterator directives . in this example we will be displaying accounts and its contacts. here is the HTML markup for the nested iteration.

<template>
        <lightning-card title="Apex Iterator Example" icon-name="custom:custom14">
            <ul class="slds-m-around_medium">
                <template iterator:it={accounts.data}>
                    <li key={it.value.Id}>
                        <div if:true={it.first} class="list-first"></div>
                        {it.value.Name}
                        <ul class="slds-m-around_medium">
                                <template iterator:it={it.value.Contacts}>
                                    <li key={it.value.Id}>
                                            <div if:true={it.first} class="list-first"></div>
                                            {it.value.Name} 
                                            <div if:true={it.last} class="list-last"></div>

                                   </li>
                                   </template>
                        </ul>
                        <div if:true={it.last} class="list-last"></div>
                    </li>
                </template>
            </ul>
        </lightning-card>
    </template>

 

Push the changes to the scratch org and reload the page. you can able to see the output as shown below and will be displayed account and its contacts.

Fire Platform Events from Batch Apex Classes

Introduction 

With winter 19 release you can able to fire the platform events from the batch apex.Batch Apex classes can opt in to fire platform events when encountering an error or exception. Clients listening on an event can obtain actionable information, such as how often the event failed and which records were in scope at the time of failure. Events are also fired for Salesforce Platform internal errors and other uncatchable Apex exceptions such as LimitExceptions, which are caused by reaching governor limits. An event record provides more granular error tracking than the Apex Jobs UI. It includes the record IDs being processed, exception type, exception message, and stack trace. You can also incorporate custom handling and retry logic for failures. You can invoke custom Apex logic from any trigger on this type of event, so Apex developers can build functionality like custom logging or automated retry handling. To fire a platform event, a batch Apex class declaration must implement the Database.RaisesPlatformEvents interface.

Step 1:  Create a Platform event

Here is the simple platform event object created for this example 

Step 2: Subscribe to platform event

I just created a simple trigger to subscribe for the platform events. During this beta release, Process Builder and flows do not support subscribing to these events.

// Trigger for listening to Cloud_News events.
trigger CloudNewsTrigger on Cloud_News__e (after insert) {    
    // List to hold all cases to be created.
    List<Case> cases = new List<Case>();
    
    
    // Iterate through each notification.
    for (Cloud_News__e event : Trigger.New) {
        if (event.Urgent__c == true) {
            // Create Case to dispatch new team.
            Case cs = new Case();
            cs.Priority = 'High';
            cs.Subject = 'News team dispatch to ' +event.Location__c;
            cases.add(cs);
        }
    }
    
    // Insert all cases corresponding to events received.
    insert cases;
}

Step 3: Raise Platform events

now you can raise the platform event from the batch apex.here is the simple batch apex that will raise the platform evens. After raising platform events all the subscribed channel will be receiving the events.

global with sharing class PlatformEventRaise implements Database.Batchable<SObject>, Database.RaisesPlatformEvents{
    // class implementation
    global Database.QueryLocator start(Database.BatchableContext BC){
        return Database.getQueryLocator('Select Id ,Name,Rating,Industry, BillingAddress,BillingStreet,BillingCity, BillingCountry, BillingPostalCode,BillingState,Phone from Account  where BillingStreet!=NULL');
    }
    
    global void execute(Database.BatchableContext BC, List<sObject> scope){
        
        List<Account> accs =(List<Account>) scope ; 
        List<Cloud_News__e> cnewList = new List<Cloud_News__e>();
        for(Account a : accs){
            // Create an instance of the event and store it in the newsEvent variable
            Cloud_News__e newsEvent = new Cloud_News__e(
                Location__c=a.BillingStreet, 
                Urgent__c=true, 
                News_Content__c=a.BillingStreet);
            cnewList.add(newsEvent) ;
            
        }
        EventBus.publish(cnewList);
        
    }
    
    global void finish(Database.BatchableContext BC){
    }
}

Go and execute batch apex

After raising the platform events, the subscribed trigger will create a case as shown below

 

Event Error Handling

The BatchApexErrorEvent object represents a platform event associated with a batch Apex class. This example creates a trigger to determine which accounts failed in the batch transaction. Custom field Dirty__c indicates that the account was one of a failing batch and ExceptionType__c indicates the exception that was encountered. JobScope and ExceptionType are fields in the BatchApexErrorEvent object.

trigger MarkDirtyIfFail on BatchApexErrorEvent (after insert) {
    Set<Id> asyncApexJobIds = new Set<Id>();
    for(BatchApexErrorEvent evt:Trigger.new){
        asyncApexJobIds.add(evt.AsyncApexJobId);
    }
    
    Map<Id,AsyncApexJob> jobs = new Map<Id,AsyncApexJob>(
        [SELECT id, ApexClass.Name FROM AsyncApexJob WHERE Id IN :asyncApexJobIds]
    );
    
    List<Account> records = new List<Account>();
    for(BatchApexErrorEvent evt:Trigger.new){
        //only handle events for the job(s) we care about
        if(jobs.get(evt.AsyncApexJobId).ApexClass.Name == 'PlatformEventRaise'){
            for (String item : evt.JobScope.split(',')) {
                Account a = new Account(
                    Id = (Id)item,
                    ExceptionType__c = evt.ExceptionType,
                    Dirty__c = true
                );
                records.add(a);
            }
        }
    }
    update records;
}

 

Apex Callouts in Read-Only Mode

let’s understand how to handler the apex callouts during the salesforce read-only mode.During read-only mode, Apex callouts to external services execute and aren’t blocked by the system. Typically, you might execute some follow-up operations in the same transaction after receiving a response from a callout. For example, you might make a DML call to update a Salesforce record. But write operations in Salesforce, such as record updates, are blocked during read-only mode. Instance refreshes result in periods of read-only mode to facilitate infrastructure upgrades. Another is site switches. Continuous site switching enables Salesforce to improve our operations and infrastructure and meet the compliance requirement of many of our customers. Planned instance refreshes and site switches will put your Salesforce org in read-only mode for a portion of your preferred maintenance windows. To check whether the org is in read-only mode, call  System.getApplicationReadWriteMode(). The following example checks the return value of System.getApplicationReadWriteMode(). If the return value is equal to ApplicationReadWriteMode.READ_ONLY enum value, the org is in read-only mode and the callout is skipped. Otherwise (ApplicationReadWriteMode.DEFAULT value), the callout is performed.

To test read-only mode in the sandbox, contact Salesforce to enable the read-only mode test option. Once the test option is enabled, you can toggle read-only mode on and verify your apps. Here is the  code

public class AccountMatchReadOnly {
    
    public class MyReadOnlyException extends Exception {}
    public void getCalloutResponseContents(List<Account> acc) {
        
        // Get Read-only mode status
        ApplicationReadWriteMode mode = System.getApplicationReadWriteMode();
        if (mode == ApplicationReadWriteMode.READ_ONLY) {
            // Prevent the callout
            throw new MyReadOnlyException('Read-only mode. Skipping callouts!');
        } else if (mode == ApplicationReadWriteMode.DEFAULT) {
            // Instantiate a new http object
            for(Account a :acc){
                String addStr = EncodingUtil.urlEncode(a.BillingStreet+','+a.BillingCity+','+a.BillingCountry , 'UTF-8');
                Http h = new Http();
                HttpRequest request = new HttpRequest();
                request.setEndpoint('https://api.addressfinder.io/api/nz/address/cleanse?key=68JQFL39HNBKDUGWTVY4&secret=MHXT7LJBWYNGPF98KRV&q='+addStr+'&format=json');
                request.setMethod('POST');
                request.setHeader('Content-Type','application/json');
                HttpResponse response = h.send(request);
                
                if (response.getStatusCode() == 200) {
                    Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
                    //System.debug('results'+results);
                    Boolean isMatched =(Boolean) results.get('matched') ; 
                    if(isMatched){
                        a.Verification_Status__c = 'Completed' ;
                        // update a ; 
                    }else{
                        a.Verification_Status__c = 'Pending' ;
                        //  update a ;     
                    }
                    
                }
            }
            update acc ;
            
        }
    }
}