Call Apex method from Lightning Web Components(LWC)

In this post, we will talk about how to Invoke Apex Controller From Lightning Web Component and how many ways we have to call the apex class/method from LWC. Lightning web components can import methods from Apex classes into the JavaScript classes using ES6 import.

import apexMethod from '@salesforce/apex/Namespace.Classname.apexMethod';
  • apexMethod -This identifies the Apex method name.
  • Classname – The Apex class name.
  • Namespace –The namespace of the Salesforce organization

Call Apex method from LWC

After importing the apex class method you can call the apex methods as functions into the component by calling either via the wire service or imperatively. To call an Apex method, a Lightning web component can:

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

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

Wire Property with Apex

As per the wire method writing rules, first we have to import method (apexMethod) from the Apex Class.

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

Then, property is wired to apexMethod in below format :-

@wire(apexMethod, { apexMethodParams }) propertyOrFunction;

Now we can get the data using {property.data} & error using {property.error} in html file.

Use Case : Business want to create one page to search all account records base on account name.

Let’s see how we can create one Lightning web component to achieve this requirement

First we need to create one apex class with @AuraEnabled

public with sharing class AccountService {
@AuraEnabled(cacheable=true)
public static List<Account> getAccounts(String strAccountName) {
  String strKey = '%'+strAccountName+'%';
   List<Account> accList = [SELECT Id,Name,AccountNumber FROM Account WHERE name like :strKey ];
   return accList;
 }
}

Then create one Lightning Web component “searchAccount” and then modify the “searchAccount.js” file to import the apex method “getAccounts” from apex class.

import { LightningElement, wire, track } from 'lwc';
import getAccounts from'@salesforce/apex/AccountService.getAccounts';
export default class SearchAccount extends LightningElement {
  @track searchKey;
  @wire (getAccounts,{strAccountName: '$searchKey'}) accounts;
  handleKeyChange(event){
    this.searchKey = event.target.value;
  }
}

During passing of the parameters, we need to put ‘$’ sign before the property.

Now we can get the data using {accounts.data} & error using {accounts.error} in html file.

<template>
	<lightning-card title="Search Account" icon-name="custom:custom57">
		<div class="slds-m-around_medium">
			<lightning-input type="search" onchange={handleKeyChange} class="slds-m-bottom_small" label="Search"></lightning-input>
			
			<template if:true={accounts.data}>
				<template for:each={accounts.data} for:item="acc">
					<lightning-layout vertical-align="center" key={acc.id}>
						<li>
							{acc.Name}
							{acc.AccountNumber}
						</li>
					</lightning-layout>
				</template>
			</template>
		</div>
	</lightning-card>
</template>

to use same LWC component on Home page modify “searchAccount.js-meta.xml” file like below.

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

Wire Function with Apex

There is another way to use wire as function. Let’s see how we can modify the above LWC component to use as Wire Function.

No changes required in Apex class and searchAccount.js-meta.xml file. We need to modify our js file. We need to defined two private reactive properties such as accounts and error. Then we need to set these two properties into the wired function named wiredAccounts.

import { LightningElement, wire, track } from 'lwc';
import getAccounts from '@salesforce/apex/AccountService.getAccounts';
export default class SearchAccount extends LightningElement {
	@track searchKey;
	@track accounts;
	@track error;

	@wire (getAccounts,{strAccountName: '$searchKey'})
	wiredAccounts({data, error}){
		if(data) {
			this.accounts =data;
			this.error = undefined;
		}else {
			this.accounts =undefined;
			this.error = error;
		}
	}

	handleKeyChange(event){
		this.searchKey = event.target.value;
	}
}

Now, we will get the Account record details using only {accounts} instead of {accounts.data} applied for wire method to property mechanism in HTML file.

<template>
	<lightning-card title="Search Account Wired Function" iconname="custom:custom57">

		<div class="slds-m-around_medium">
			<lightning-input type="search" onchange={handleKeyChange} class="slds-m-bottom_small" label="Search"></lightning-input>
			<template if:true={accounts}>
				<template for:each={accounts} for:item="acc">
					<lightning-layout vertical-align="center" key={acc.id}>
						<li>
							{acc.Name}
							{acc.AccountNumber}
						</li>
					</lightning-layout>
				</template>
			</template>
		</div>
	</lightning-card>
</template>

Imperative Method with Apex

Now we have a good understanding of using wire mechanism in Lightning Web Component. Let’s talk about how to get salesforce data with imperative service. Here is example of LWC call Apex method with parameters imperatively.

NOTE :- For Imperative method we dont need to mark the apex method as cacheabe=true.

Let’s modify the above example into the imperative mechanism. We need to modify our js file like below

import { LightningElement, track } from 'lwc';
importgetAccounts from '@salesforce/apex/AccountService.getAccounts';
export default class SearchAccount extends LightningElement {
	@track accounts;
	@track error;
	handleKeyChange(event){
		constsearchKey = event.target.value;
		getAccounts({ strAccountName: searchKey })
		.then(result => {
			this.accounts = result;
			this.error = undefined;
		})
		.catch(error => {
			this.error = error;
			this.accounts = undefined;
		})
	} 
}

Wire Vs Imperative

Always prefer to use @wire over imperative Apex method invocation. @wire fits nicely in the overall Lightning Web Component reactive architecture as per lightning web component best practices.

However, we have some use cases where we require to use imperative Apex. For example, when you need to invoke an Apex method without responsive parameters in response to a specific event, like a button click event to get record.

Now we know @wire is recommended way by Salesforce but we have two way to implements @wire an apex method

  • Wire an Apex method as property.
  • Wire an Apex Method as function.

Now, which one is recommended? Prefer way is us @wire as property.

Here is some consideration

  • First, import the Apex method into the JS
  • If it is wired, make sure cacheable=trued ecorator is set
  • Parameters are passed as an object
  • For simple results: wire to a property
  • For some processing: wire to a function
  • For controlling when to call: imperative

Working on Apex in LWC

YouTube video

Further Reading

To learn more about lightning web component check this link https:/​/​developer. salesforce.​com/​docs/​component-​library/​documentation/​lwc

Amit Chaudhary
Amit Chaudhary

Amit Chaudhary is Salesforce Application & System Architect and working on Salesforce Platform since 2010. He is Salesforce MVP since 2017 and have 17 Salesforce Certificates.

He is a active blogger and founder of Apex Hours.

Articles: 461

3 Comments

Leave a Reply

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