Let’s discuss here what all the different ways we can able to use the wire services in the lightning web component world. To read Salesforce data, Lightning web components use a reactive wire service, which is built on Lightning Data Service. Components use @wire
in their JavaScript class to read data from one of the wire adapters in the lightning/ui*
Api
modules and also to call the apex controller server-side methods using wire services. The wire service provisions an immutable stream of data to the component. Each value in the stream is a newer version of the value that precedes it.
We call the wire service reactive in part because it supports reactive variables, which are prefixed with $
. If a reactive variable changes, the wire service provisions new data. We say “provisions” instead of “requests” or “fetches” because if the data exists in the client cache, a network request may not be involved. The wire service delegates control flow to the Lightning Web Components engine. Delegating control is great for read operations, but it isn’t great for create, update, and delete operations. As a developer, you want complete control over operations that change data. That’s why you perform create, update, and delete operations with a JavaScript API instead of with the wire service.
Wire Service Syntax
Wire Service Syntax contains two steps. First Part is importing wire adapter and the second one is wire Decorator.
Import a wire adapter using named import syntax.
import { wire} from 'lwc';
Decorate a property or function with @wire
and specify the wire adapter. Each wire adapter defines a data type.
@wire(adapterId, adapterConfig) propertyOrFunction;
Import References to Salesforce Objects and Fields
lightning/ui*Api
modules, you can import the references to objects and fields. Salesforce verifies that the objects and fields exist, prevents objects and fields from being deleted, and cascades any renamed objects and fields into your component’s source code. It also ensures dependent objects and fields are included in change sets and packages. Importing references to objects and fields ensures that your code works, even when object and field names change.To access object and field API names, use an import
statement. All object and field imports come from @salesforce/
schema
scoped packages.To import a reference to an object, use this syntax.
import objectName from '@salesforce/schema/object';
For Example, importing an object using a wire adapter it looks like below
import POSITION_OBJECT from '@salesforce/schema/Position__c';
To import a reference to a field, use this syntax.
import FIELD_NAME from '@salesforce/schema/object.field';
For Example, importing a Field using wire adapter it looks like below.
import ACCOUNT_NAME_FIELD from '@salesforce/schema/Account.Name';
To import a reference to a field via a relationship, use this syntax. You can specify up to 5 levels of spanning fields.
import SPANNING_FIELD_NAME from '@salesforce/schema/object.relationship.field';
For Example, importing the relationship fields looks like as shown below .
import ACCOUNT_OWNER_NAME_FIELD from '@salesforce/schema/Account.Owner.Name';
The following code imports the Account.Name
field and uses it in a wire adapter’s configuration object. When we call this code the wire service get the data from the Salesforce account object which is similar like below SOQL “Select Id,Name from Account Where Id=’001xxxx”
import { LightningElement, api, wire } from 'lwc'; import { getRecord } from 'lightning/uiRecordApi'; import ACCOUNT_NAME_FIELD from '@salesforce/schema/Account.Name'; export default class Record extends LightningElement { @api recordId; @wire(getRecord, { recordId: '$recordId', fields: [ACCOUNT_NAME_FIELD] }) record; }
Mark a Configuration Object Property as Dynamic and Reactive
In the wire adapter’s configuration object, prefix a value with $
to reference a property of the component instance. The $
prefix tells the wire service to treat it as a property of the class and evaluate it as this.propertyName
. The property is reactive. If the property’s value changes, new data is provisioned and the component rerenders.The following example get the contact record data using the wire service
import { LightningElement, api,track, wire } from 'lwc'; import { getRecord } from 'lightning/uiRecordApi'; const fields = [ 'Contact.Name', 'Contact.Title', 'Contact.Phone', 'Contact.Email', ]; export default class Recordex extends LightningElement { @api recordId; @track contact; @wire(getRecord, { recordId: '$recordId', fields }) contact; get name() { return this.contact.data.fields.Name.value; } get title() { return this.contact.data.fields.Title.value; } get phone() { return this.contact.data.fields.Phone.value; } get email() { return this.contact.data.fields.Email.value; } }
<template> <template if:true={contact.data}> <div class="slds-m-around_medium"> <p>{name}</p> <p>{title}</p> <p> <lightning-formatted-phone value={phone}></lightning-formatted-phone> </p> <p> <lightning-formatted-email value={email}></lightning-formatted-email> </p> </div> </template> </template>
Decorate a Property with @wire
Wiring a property is useful when you want to consume the data or error as-is. If the property decorated with @wire
is used as an attribute in the template and its value changes, the wire service provisions the data and triggers the component to rerender. The property is private, but reactive, like a property decorated with @track
.This code applies @wire
to the record
property.
import { LightningElement, api, wire } from 'lwc'; import { getRecord } from 'lightning/uiRecordApi'; import ACCOUNT_NAME_FIELD from '@salesforce/schema/Account.Name'; export default class Record extends LightningElement { @api recordId; @wire(getRecord, { recordId: '$recordId', fields: [ACCOUNT_NAME_FIELD] }) record; }
The property is assigned a default value after component construction and before any other lifecycle event. The default value is an object with data
and error
properties of undefined
. Therefore, you can access the property’s value in any function, including functions used by the template or used as part of the component’s lifecycle.The object supplied to the property (in this example, record
) has this shape
data
(Any type)—The value supplied by the adapter.error
(Error)—An error if the adapter wasn’t able to supply the requested data or if the adapter wasn’t found. Otherwise, this property isundefined
.
When data becomes available from the wire adapter, it’s set in the data
property (error
remains undefined
). When newer versions of the data are available, data
is updated.If an error occurs in the adapter, for example when retrieving the data, error
is populated with an error object (data
is set to undefined
). You can use one @wire
output as another @wire
input. For example, you could use $record.data.fieldName
as an input to another wire adapter.
Decorate a Function with @wire
Wiring a function is useful to perform logic whenever new data is provided or when an error occurs. The wire service provisions the function an object with error
and data
properties, just like a wired property. The function is invoked whenever a value is available, which can be before or after the component is connected or rendered.
import { LightningElement, api, track, wire } from 'lwc'; import { getRecord } from 'lightning/uiRecordApi'; export default class WireFunction extends LightningElement { @api recordId; @track record; @track error; @wire(getRecord, { recordId: '$recordId', fields: ['Account.Name'] }) wiredAccount({ error, data }) { if (data) { this.record = data; this.error = undefined; } else if (error) { this.error = error; this.record = undefined; } } get name() { return this.record.fields.Name.value; } }
Call Apex Methods using wire service
Lightning web components can import methods from Apex classes. The imported methods are functions that the component can call either via @wire
or imperatively. For example, to return a simple list of accounts, it would be best to use getListUi
. But to use a SOQL query to select certain accounts, you have to use an Apex method. When an Apex class name changes outside of the JavaScript source file, the class name is automatically updated in the JavaScript source file. Method and argument name changes aren’t updated in the JavaScript source file.
To call an Apex method, a Lightning web component can:
- Wire a property
- Wire a function
Lets discuss here how to call the below contact controller in the LWC component using the wire service adapter.
public with sharing class ContactController { @AuraEnabled(cacheable=true) public static List<Contact> getContactList() { return [SELECT Id, Name, Title, Phone, Email, Picture__c FROM Contact WHERE Picture__c != null LIMIT 10]; } }
The below 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 using the wire property .
import { LightningElement, wire } from 'lwc'; import getContactList from '@salesforce/apex/ContactController.getContactList'; export default class ApexWireMethodToProperty extends LightningElement { @wire(getContactList) contacts; }
The below 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 tracked and used in the template. If it provisions error
, it’s assigned to this.error
, which is also tracked and used in the template. If the value of a tracked property changes, the template rerenders.
import { LightningElement, wire, track } from 'lwc'; import getContactList from '@salesforce/apex/ContactController.getContactList'; export default class ApexWireMethodToFunction extends LightningElement { @track contacts; @track error; @wire(getContactList) wiredContacts({ error, data }) { if (data) { this.contacts = data; this.error = undefined; } else if (error) { this.error = error; this.contacts = undefined; } } }
Using lightning/ui*Api Wire Adapters
Wire adapters and JavaScript functions in these modules are built on top of Lightning Data Service (LDS) and User Interface API. Use these wire adapters and functions to work with Salesforce data and metadata . Here is are the some of the useful wire adapters
getListUi
Use this wire adapter to get the records and metadata for a list view . For Example, the following wire adapter gets the allaccounts list view data.
@wire(getListUi, { objectApiName: ACCOUNT_OBJECT, listViewApiName: 'AllAccounts' })
getObjectInfo
Use this wire adapter to get metadata about a specific object. The response includes metadata describing fields, child relationships, record type, and theme. The following example shows how to get the account object data using the wire adapter .
@wire(getObjectInfo, { objectApiName: ACCOUNT_OBJECT })
getPicklistValues
Use this wire adapter to get the picklist values for a specified field. the following wire adapter shows how to get the picklist value .
@wire(getPicklistValues, { recordTypeId: '012000000000000AAA', fieldApiName: INDUSTRY_FIELD })
getPicklistValuesByRecordType
Use this wire adapter to get the values for every picklist of a specified record type.
@wire(getPicklistValuesByRecordType, { objectApiName: ACCOUNT_OBJECT, recordTypeId: '012000000000000AAA' })
getRecord
Use this wire adapter to get a record’s data.
@wire(getRecord, { recordId: '001456789012345678', fields: [NAME_FIELD] })
getRecordUi
Use this wire adapter to get layout information, metadata, and data to build UI for one or more records.
@wire(getRecordUi, { recordIds: ['001456789012345678', '001456789087654321'], layoutTypes: ['Full'], modes: ['View'] })