SalesforceBlue

Feel the rhythm of Salesforce

LWC

Using Apex In Lightning Web Component Simplified

Lightning web components can import methods from Apex classes. The imported methods are functions that the component can call either via @wire or imperatively.

Wire Apex Methods to Lightning Web Components:

To use @wire to call an Apex method, annotate the Apex method with @AuraEnabled(cacheable=true). Please note in such an Apex method DML can’t be performed.

A client-side Lightning Data Service cache is checked before issuing the network call to invoke the Apex method on the server. To refresh stale data, call refreshApex(), because Lightning Data Service doesn’t manage data provisioned by Apex.

Use the below syntax to import an Apex method and wire it to a component:

import apexMethodName from '@salesforce/apex/Namespace.Classname.apexMethodReference';
@wire(apexMethodName, { apexMethodParams })
propertyOrFunction;
  • apexMethodName—A symbol that identifies the Apex method.
  • apexMethodReference—The name of the Apex method to import.
  • Classname—The name of the Apex class.
  • 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.
  • apexMethodParams—An object with properties that match the parameters of the apexMethod, if needed. If a parameter value is null, the method is called. If a parameter value is undefined, the method isn’t called. If the Apex method is overloaded, the choice of what method to call is non-deterministic (effectively random), and the parameters passed may cause errors now or in the future. Don’t overload @AuraEnabled Apex methods.
  • propertyOrFunction—A private property or function that receives the stream of data from the wire service. If a property is decorated with @wire, the results are returned to the property’s data property or error property. If a function is decorated with @wire, the results are returned in an object with a data property or an error property.
Wire an Apex Method to a Property:

Let’s create a Component(LWC) to understand this.

Before that create an Apex class with the following code.

public with sharing class AccountController {
    
    @AuraEnabled(cacheable=true)
    public static List<Opportunity> getTopOpportunities(Id accountId){
        try {
            return [
                SELECT Id, Name 
                FROM Opportunity 
                WHERE Amount > 10000 AND AccountId =:accountId LIMIT 10
            ];            
        } catch (Exception e) {
            throw new AuraHandledException(e.getMessage());
        }
    }

}

Create a new component (LWC) with the name topOpptyLwc. This component will show the top opportunities for a given account.

Add the following code to the created component:

import { LightningElement, api, wire } from 'lwc';
import getTopOpportunities from '@salesforce/apex/AccountController.getTopOpportunities';

export default class TopOpptyLwc extends LightningElement {

    @api recordId;

    @wire(getTopOpportunities, {accountId: '$recordId'})
    record;

}

In the above code block, we have imported the reference for our Apex method at Line 2.

At Line 8 we are decorating the record property with @wire and adding the function to be invoked along with the apex method params.

<template>
    <lightning-card title="Top Opportunities">
        <p class="slds-p-horizontal_small">
            <template if:true={record.data}>
                <template for:each={record.data} for:item="oppty">
                    <p key={oppty.Id}>{oppty.Name}</p>
                </template>
            </template>
        </p>
    </lightning-card>
</template>

In the above code block, we are iterating over the return data from the wire service and displaying the opportunity information.

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

Add this component to Account’s record page. You will get an output like the below:


Wire an Apex Method to a Function:

Let’s update the component created above to understand the wiring apex method to a function. Add the following code to your component – topOpptyLwc

import { LightningElement, api, wire } from 'lwc';
import getTopOpportunities from '@salesforce/apex/AccountController.getTopOpportunities';

export default class TopOpptyLwc extends LightningElement {

    @api recordId;
    records;
    error;

    @wire(getTopOpportunities, {accountId: '$recordId'})
    wiredData({error, data}) {
        if(data) {
            this.records = data;
            this.error = undefined;
        } else if(error) {
            this.error = error;
            this.records = undefined;
        }
    }

}

In the above code block at line 10, we are wiring the Apex method to a function. In this case, the results are provisioned to a function, the JavaScript can operate on the results.

Also, the template accesses the data a bit differently than if results were provisioned to a property.

<template>
    <lightning-card title="Top Opportunities">
        <p class="slds-p-horizontal_small">
            <template if:true={records}>
                <template for:each={records} for:item="oppty">
                    <p key={oppty.Id}>{oppty.Name}</p>
                </template>
            </template>
        </p>
    </lightning-card>
</template>
Call Apex Method Imperatively:

To control when the method invocation occurs (for example, in response to clicking a button), call the method imperatively. When you call a method imperatively, you receive only a single response.

Compare this behavior with @wire, which delegates control to the framework and results in a stream of values being provisioned.

In the following scenarios, you must call an Apex method imperatively as opposed to using @wire.

  • To call a method that isn’t annotated with cacheable=true, which includes any method that inserts, updates, or deletes data.
  • To control when the invocation occurs.
  • To work with objects that aren’t supported by User Interface API, like Task and Event.
  • To call a method from an ES6 module that doesn’t extend LightningElement

If an Apex method is marked with @AuraEnabled(cacheable=true), a client-side Lightning Data Service cache is checked before issuing the network call to invoke the Apex method on the server.

However, Lightning Data Service doesn’t manage data provisioned by Apex. Therefore, to refresh stale data, invoke the Apex method and then call getRecordNotifyChange() to update the Lightning Data Service cache.

Let’s update the topOpptyLwc example implemented above by calling the Apex method imperatively at the click of a button. Please update the component with the following code:

import { LightningElement, api } from 'lwc';
import getTopOpportunities from '@salesforce/apex/AccountController.getTopOpportunities';

export default class TopOpptyLwc extends LightningElement {

    @api recordId;
    records;
    error;

    getTopOppty() {
            getTopOpportunities({accountId: this.recordId}).then((data) => {
                this.records = data;
                this.error = undefined;
            })
            .catch((error) => {
                this.error = error;
                this.data = undefined
            })
    }
}

At line 11 we are invoking the Apex function and passing the required params. This imported function returns a promise.

If you wanted to learn more about Promises in Javascript then refer this great article – Promise

<template>
    <lightning-card title="Top Opportunities">
        <lightning-button variant="brand" label="Get Top Oppty" title="Get Top Oppty" onclick={getTopOppty} slot="actions"></lightning-button>
        <p class="slds-p-horizontal_small">
            <template if:true={records}>
                <template for:each={records} for:item="oppty">
                    <p key={oppty.Id}>{oppty.Name}</p>
                </template>
            </template>
        </p>
    </lightning-card>
</template>

Refresh the account record page and notice the behaviour. Now on click of a button the top opportunities are loaded.

Thank you for visiting SalesforceBlue.com
If you have any queries feel free to write down a comment below 🙂


Leave a Reply

Your email address will not be published. Required fields are marked *