Call Apex Methods 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 notifyRecordUpdateAvailable(recordIds) to update the Lightning Data Service cache.
Let’s look at the apexImperativeMethod component from the lwc-recipes repo that uses the same getContactList
class as our previous examples. Instead of wiring it, when a user clicks a button, the component calls getContactList()
.
The imported function returns a promise. This code provides a one-time resolution given a set of parameters, whereas @wire(apexMethod)
provides a stream of values and supports dynamic parameters.
The template uses lwc:if
to render the list of contacts. It also uses for:each
to iterate over the contacts.
Pass parameters values to an Apex method in an object whose properties match the parameters of the Apex method. For example, if the Apex method takes a string parameter, don’t pass a string directly. Instead, pass an object that contains a property whose value is a string.
To call a method with an object parameter, check out the apexImperativeMethodWithComplexParams
component in the lwc-recipes repo.
When you pass values such as record data from LWC to Apex, use JavaScript objects or arrays. Map values are not serialized when passed to Apex methods.
Using maps isn’t supported for both imperative and wired Apex calls. The improper use of maps, such as with map[key] = val
, allowed the data to be passed with LWS disabled. However, this usage no longer works when LWS is enabled. Furthermore, map.set(key, val)
isn’t supported for passing values to Apex.
You can use a JavaScript object like this.
When you call Apex imperatively, use the try/catch block to handle errors.
Alternatively, you can also use the syntax of a promise like this.
The Apex method calls the then
or catch
block depending if there's an error. Calling the then
and catch
blocks happens asynchronously, so you can't put the whole getContactList()
method within a try-catch block.
In this case, the catch
block handle errors from both the Apex method and the then
block. If the getContactList()
Apex method throws an exception, you can handle it in the catch
block. If the Apex method runs successfully, your code in the then
runs next. And if there's an error in the then
block, you can also handle it in the catch
block. See Handle Errors from Apex.
See Also
- Wire Apex Methods to Lightning Web Components
- getRecordNotifyChange(recordIds) (Deprecated)
- Alternatives to Mutating Objects
- MDN Web Docs: Rewriting a Promise chain with an async function