Wire Apex Methods to Lightning Web Components

To read Salesforce data, Lightning web components use a reactive wire service. Use @wire in a component’s JavaScript class to specify an Apex method. You can @wire a property or a function to receive the data. To operate on the returned data, @wire a function.

To use @wire to call an Apex method, annotate the Apex method 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. To refresh stale data, call refreshApex(), because Lightning Data Service doesn’t manage data provisioned by Apex.

Use this syntax to import an Apex method and wire it to a component.

1import apexMethodName from '@salesforce/apex/namespace.classname.apexMethodReference';
2@wire(apexMethodName, { apexMethodParams })
3propertyOrFunction;
  • 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.

    apexMethodParams is an object. To pass parameter values to an Apex method, pass 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. Using maps isn’t supported for both imperative and wired Apex calls. See Pass Values to Apex.

    Important

  • 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.

    The data property and the error property are hardcoded values in the API. You must use these values.

    Note

The return value from Apex is serialized if it contains a decimal value. If the decimal value has more than 15 digits of precision, the value is serialized as a JSON string to preserve exact precision. Otherwise, the value is serialized as a JSON number literal. This serialization prevents precision loss for high-precision decimal values that exceed JavaScript's double precision limits. You can handle these values as strings in JavaScript and convert the values as needed.

Wire an Apex Method to a Property 

Let’s look at the apexWireMethodToProperty component from the lwc-recipes repo. This component prints a list of contacts returned by an Apex method.

A list of contacts in the LWC recipes app.

To get its data, the component wires an Apex method. The Apex method makes a SOQL query that returns a list of contacts that each have a picture. (This component doesn’t render the pictures, but other sample components do.) As we’ve learned, to return a simple list of contacts, it’s best to use getListUi. But to use a SOQL query to select certain records, we must use an Apex method.

Remember that the method must be static, and global or public. The method must be decorated with @AuraEnabled(cacheable=true).

1public with sharing class ContactController {
2    @AuraEnabled(cacheable=true)
3    public static List<Contact> getContactList() {
4        return [
5            SELECT Id, Name, Title, Phone, Email, Picture__c
6            FROM Contact
7            WHERE Picture__c != null
8            WITH SECURITY_ENFORCED
9            LIMIT 10
10        ];
11    }
12}

The component’s JavaScript code imports the Apex method and invokes it via the wire service. The wire service either provisions the list of contacts to the contacts.data property, or returns an error to the contacts.error property.

apexWireMethodToProperty.js
1import { LightningElement, wire } from 'lwc';
2import getContactList from '@salesforce/apex/ContactController.getContactList';
3
4export default class ApexWireMethodToProperty extends LightningElement {
5    @wire(getContactList) contacts;
6}

The template uses the lwc:if directive to check whether the contacts.data property is truthy. If it is, it iterates over it and renders the name of each contact. If contacts.error is truthy, the component renders <c-error-panel>.

1<!-- apexWireMethodToProperty.html -->
2<template>
3  <lightning-card title="ApexWireMethodToProperty" icon-name="custom:custom63">
4    <div class="slds-m-around_medium">
5      <template lwc:if={contacts.data}>
6        <template for:each={contacts.data} for:item="contact">
7          <p key={contact.Id}>{contact.Name}</p>
8        </template>
9      </template>
10      <template lwc:elseif={contacts.error}>
11        <c-error-panel errors={contacts.error}></c-error-panel>
12      </template>
13    </div>
14  </lightning-card>
15</template>

Wire an Apex Method with a Dynamic Parameter 

Now let’s wire an Apex method that takes a parameter. This component is also in the lwc-recipes repo.

A search field with the letters "Jo" and two contacts listed below it, Michael Jones and Jonathan Bradley.

The Apex method takes a string parameter called searchKey, and returns a list of contacts whose name contains the string.

1// ContactController.cls
2public with sharing class ContactController {
3    @AuraEnabled(cacheable=true)
4    public static List<Contact> findContacts(String searchKey) {
5        String key = '%' + searchKey + '%';
6        return [
7            SELECT Id, Name, Title, Phone, Email, Picture__c
8            FROM Contact
9            WHERE Name LIKE :key AND Picture__c != null
10            WITH USER_MODE
11            LIMIT 10
12        ];
13    }
14}

The component’s JavaScript prefaces the value of the searchKey parameter with $ to indicate that it’s dynamic and reactive. It references a property of the component instance. If its value changes, the template rerenders.

To @wire the component to the Apex method, the first parameter is a string, which is the name of the Apex method—in this case, findContacts. The second @wire parameter is an object that contains the parameters to pass to the Apex method. So, for example, even though findContacts takes a string, we don’t pass a string as the second @wire parameter. Instead, we pass an object that contains a property whose value is a string: { searchKey: '$searchKey' }. (If the Apex method took another parameter, we would add another property to the object.)

Important

apexWireMethodWithParams.js
1import { LightningElement, wire } from 'lwc';
2import findContacts from '@salesforce/apex/ContactController.findContacts';
3
4/** The delay used when debouncing event handlers before invoking Apex. */
5const DELAY = 300;
6
7export default class ApexWireMethodWithParams extends LightningElement {
8    searchKey = '';
9
10    @wire(findContacts, { searchKey: '$searchKey' })
11    contacts;
12
13    handleKeyChange(event) {
14        // Debouncing this method: Do not update the reactive property as long as this function is
15        // being called within a delay of DELAY. This is to avoid a very large number of Apex method calls.
16        window.clearTimeout(this.delayTimeout);
17        const searchKey = event.target.value;
18        // eslint-disable-next-line @lwc/lwc/no-async-operation
19        this.delayTimeout = setTimeout(() => {
20            this.searchKey = searchKey;
21        }, DELAY);
22    }
23}

The template uses searchKey as the value of the <lightning-input> field.

1<!-- apexWireMethodWithParams.html -->
2<template>
3  <lightning-card title="ApexWireMethodWithParams" icon-name="custom:custom63">
4    <div class="slds-m-around_medium">
5      <lightning-input
6        type="search"
7        onchange={handleKeyChange}
8        class="slds-m-bottom_small"
9        label="Search"
10        value={searchKey}
11      ></lightning-input>
12      <template lwc:if={contacts.data}>
13        <template for:each={contacts.data} for:item="contact">
14          <p key={contact.Id}>{contact.Name}</p>
15        </template>
16      </template>
17      <template lwc:elseif={contacts.error}>
18        <c-error-panel errors={contacts.error}></c-error-panel>
19      </template>
20    </div>
21  </lightning-card>
22</template>

To watch a walk though of this sample code, see Wire an Apex Method to a Property in the Lightning Web Components Video Gallery.

Tip

Wire an Apex Method with Complex Parameters 

This example demonstrates how to call an Apex method that takes an object as a parameter. The @wire syntax is the same for any Apex method, but this example shows a pattern for building and passing an object.

The component has three input fields that take a string, a number, and a number of list items that the component uses to generate a list. The Apex method simply concatenates and returns a string based on the values. When an input value changes, the @wire calls the Apex method and provisions new data.

Form that gathers multiple data types to send to Apex.

1<!-- apexWireMethodWithComplexParams.html -->
2<template>
3  <lightning-card title="ApexWireMethodWithComplexParams" icon-name="custom:custom63">
4    <div class="slds-var-m-around_medium">
5      <lightning-input
6        label="String"
7        type="string"
8        value={stringValue}
9        class="string-input"
10        onchange={handleStringChange}
11      ></lightning-input>
12      <lightning-input
13        label="Number"
14        type="number"
15        min="0"
16        max="100"
17        value={numberValue}
18        class="number-input"
19        onchange={handleNumberChange}
20      ></lightning-input>
21      <lightning-input
22        label="List items"
23        type="number"
24        min="0"
25        max="10"
26        value={listItemValue}
27        class="list-item-input"
28        onchange={handleListItemChange}
29      ></lightning-input>
30      <br />
31      <template lwc:if={apexResponse.data}>
32        <p>{apexResponse.data}</p>
33      </template>
34    </div>
35    <template lwc:elseif={apexResponse.error}>
36      <c-error-panel errors={error}></c-error-panel>
37    </template>
38  </lightning-card>
39</template>

The Apex method takes an object, CustomWrapper.

ApexTypesController.cls
1public with sharing class ApexTypesController {
2    @AuraEnabled(cacheable=true)
3    public static String checkApexTypes(CustomWrapper wrapper) {
4        // Using System.debug() isn't good practice for production applications.
5        // It's used here to showcase how the received data looks like in Apex.
6        System.debug(wrapper);
7        // The values are based on the data that is defined in the
8        // apexImperativeMethodWithComplexParams Lightning web component.
9        String response =
10            'You entered "' +
11            wrapper.someString +
12            '" as String, and "' +
13            wrapper.someInteger +
14            '" as Integer value. The list contained ' +
15            wrapper.someList.size() +
16            ' items.';
17        return response;
18    }
19}
CustomWrapper.cls
1/**
2 * Wrapper class used to demonstrate how we can pass complex paramters from LWC.
3 */
4public with sharing class CustomWrapper {
5    @AuraEnabled
6    public Integer someInteger { get; set; }
7    @AuraEnabled
8    public String someString { get; set; }
9    @AuraEnabled
10    public List<String> someList { get; set; }
11}

To pass parameter values from a component to an Apex method, use an object. In this example, the Apex method takes an object, CustomWrapper, so the component builds a matching object to pass in the @wire.

apexWireMethodWithComplexParams.js
1import { LightningElement, wire } from 'lwc';
2import checkApexTypes from '@salesforce/apex/ApexTypesController.checkApexTypes';
3
4export default class ApexWireMethodWithComplexParams extends LightningElement {
5    listItemValue = 0;
6    numberValue = 50;
7    stringValue = 'Some string';
8
9    parameterObject = {
10        someString: this.stringValue,
11        someInteger: this.numberValue,
12        someList: []
13    };
14
15    @wire(checkApexTypes, { wrapper: '$parameterObject' })
16    apexResponse;
17
18    handleStringChange(event) {
19        this.parameterObject = {
20            ...this.parameterObject,
21            someString: (this.stringValue = event.target.value)
22        };
23    }
24
25    handleNumberChange(event) {
26        this.parameterObject = {
27            ...this.parameterObject,
28            someInteger: (this.numberValue = parseInt(event.target.value, 10))
29        };
30    }
31
32    handleListItemChange(event) {
33        const someList = [];
34        for (let i = 0; i < event.target.value; i++) {
35            someList.push(this.stringValue);
36        }
37        this.parameterObject = {
38            ...this.parameterObject,
39            someList
40        };
41    }
42}

Wire an Apex Method to a Function 

Now let’s look at the apexWireMethodToFunction component from the lwc-recipes repo. This component wires an Apex method call to a function. Because 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.

The rendered component is the same as apexWireMethodToProperty (except for the header).

A list of contacts in the LWC recipes app.

This component calls the same Apex method as apexWireMethodToProperty. The method must be static, and global or public. The method must be decorated with @AuraEnabled(cacheable=true).

1// ContactController.cls
2public with sharing class ContactController {
3    @AuraEnabled(cacheable=true)
4    public static List<Contact> getContactList() {
5        return [
6            SELECT Id, Name, Title, Phone, Email, Picture__c
7            FROM Contact
8            WHERE Picture__c != null
9            WITH USER_MODE
10            LIMIT 10
11        ];
12    }
13}

The component’s JavaScript code imports the Apex method and invokes it via the wire service. The wire service provisions the results to the wiredContacts() function via an object with either an error or data property. If the wire service provisions data, it’s assigned to this.contacts, which is used in the template. If it provisions error, it’s assigned to this.error, which is also used in the template. If the value of these properties change, the template rerenders.

apexWireMethodToFunction.js
1import { LightningElement, wire } from 'lwc';
2import getContactList from '@salesforce/apex/ContactController.getContactList';
3
4export default class ApexWireMethodToFunction extends LightningElement {
5    contacts;
6    error;
7
8    @wire(getContactList)
9    wiredContacts({ error, data }) {
10        if (data) {
11            this.contacts = data;
12            this.error = undefined;
13        } else if (error) {
14            this.error = error;
15            this.contacts = undefined;
16        }
17    }
18}

The template uses the lwc:if directive to check for the JavaScript contacts property. If it exists, it iterates over it and renders the name of each contact. If the error property exists, the component renders <c-error-panel>.

1<!-- apexWireMethodToFunction.html -->
2<template>
3  <lightning-card title="ApexWireMethodToFunction" icon-name="custom:custom63">
4    <div class="slds-m-around_medium">
5      <template lwc:if={contacts}>
6        <template for:each={contacts} for:item="contact">
7          <p key={contact.Id}>{contact.Name}</p>
8        </template>
9      </template>
10      <template lwc:elseif={error}>
11        <c-error-panel errors={error}></c-error-panel>
12      </template>
13    </div>
14  </lightning-card>
15</template>

Work with Multiple Wire Methods 

To execute multiple wires consecutively, retrieve data from the first wire and use that data to retrieve more data from the second wire. To ensure that the wires execute consecutively, wait until the first wire completes before you set the required parameters for the second wire. For example, pass a property into the first wire, and then use that property with a second property for the second wire. Then use both properties in a separate function.

1property1;
2property2;
3@wire(myApexMethod1, {})
4method1result({ data, error }) {
5  if(data) {
6    this.property1 = data;
7    // call another function
8    // to do something with property1 and property2
9  }
10}
11@wire(myApexMethod2, {})
12method2result({ data, error }) {
13  if(data) {
14    this.property2 = data;
15    // call another function
16    // do something with property1 and property2
17  }
18}

To pass in a property value that's dependent on a previous wire call, make the property reactive so that the wire provisions new data when the property's value changes. For an example, see getPicklistValues.

1property1;
2property2;
3
4  @wire(myWireCall, { objectApiName: ACCOUNT_OBJECT })
5  results({ error, data }) {
6    if (data) {
7      this.property1 = data.someField;
8      this.error = undefined;
9    } else if (error) {
10      this.error = error;
11      this.property1 = undefined;
12    }
13  }
14
15  @wire(myOtherWireCall, { recordTypeId: "$property1", fieldApiName: RATING_FIELD })
16  picklistResults({ error, data }) {
17    if (data) {
18      this.property2 = data;
19      this.error = undefined;
20    } else if (error) {
21      this.error = error;
22      this.property2 = undefined;
23    }
24  }
25
26  doSomething() {
27  // do something with property1 and property2
28}

To work with multiple Apex method calls and then process the results when the component loads, you can call a common function when both property values are available.

See Also