Using Wire Adapter & JS APIs in LWC – Salesforce
There are multiple ways to interact with Salesforce Data in LWC. One such method is using wire adapter & JS APIs in LWC.
Before using wire adapter & JS APIs in LWC, we encourage you to read our earlier posts on using LWC base components to work with Salesforce Data. We should always try to use standard base components for most of our requirements, if standard components are not suitable for your use case use the wire adapter & JS APIs for more customization over base components.
Different wire adapters work on Salesforce Data and Metadata like individual records, lists of records, objects and layout schema. The lightning wire adapters are part of the lightning/ui*api module.
Today, we are going to discuss how to :
- Create Record using wire adapter & JS APIs in LWC.
- Update Record using wire adapter & JS APIs in LWC.
- Fetch Record Data using wire adapters & JS APIs in LWC.
- Delete Salesforce Record using wire adapter & JS APIs in LWC.
Create Record using wire adapter & JS APIs in LWC
Use createRecord wire adapter to create a record in Salesforce. All you need to do is pass the API name of the Object you want to create and JSON of fields (API Names) and their respective values.
Syntax
Import the createRecord adapter along with the ‘lwc’ module.
import { LightningElement } from 'lwc';
import { createRecord } from 'lightning/uiRecordApi';
Import References to the Object that you want to create and the fields you want to assign values to.
import ACCOUNT_OBJECT from '@salesforce/schema/Account';
import NAME_FIELD from '@salesforce/schema/Account.Name';
HTML Code
<template>
<lightning-input name="name" type="text" onchange={handleChange}></lightning-input>
<button onclick={createAccount}>Create</button>
</template>
JS Code
import { LightningElement } from 'lwc';
import { createRecord } from 'lightning/uiRecordApi';
import ACCOUNT_OBJECT from '@salesforce/schema/Account';
import NAME_FIELD from '@salesforce/schema/Account.Name';
export default class CreateRecordExample extends LightningElement {
name;
//gets called when value changed in lightning-input field
handleChange(event){
this.name = event.target.value;
}
//gets called on button click from html
createAccount() {
const fields = {};
fields[NAME_FIELD.fieldApiName] = this.name;
const recordInput = { apiName:ACCOUNT_OBJECT.objectApiName, fields };
//call the createRecord function by passing the account api name and the field value pair
createRecord(recordInput)
//gets called when record is successfully created
.then(account => {
this.accountId = account.id;
//show a toast message in the UI on success
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Account created',
variant: 'success',
}),
);
})
//gets called when there is an error creating record
.catch(error => {
//show a toast message in the UI on error
this.dispatchEvent(
new ShowToastEvent({
title: 'Error creating record',
message: error.body.message,
variant: 'error',
}),
);
});
}
}
Explanation
Step 1: Import the createRecord function from the lightning/uiRecordApi module
Step 2: Import references to the Object and the Fields which you want to create a record for.
Step 3: The HTML file contains a lighting-input field of type text which accepts the user data. There is also a button created to call the js function and create the account record.
Step 4: The JS file assigns a value inserted in the lightning-input field using the onchange handler function handleChange. The value is saved in the name variable.
On click of the Create button createAccount function is called, here we construct the JSON structure of fieldApiName and the value for the field. This JSON structure is data that will be saved in the Account Object.
We then call the createRecord function and pass the account API name (we need to tell the function which object we are creating a record for) and the JSON structure created above.
Comparison for easy understanding.
Apex Code
Account accRec = new Account();
accRec.Name = 'Test Account';
insert accRec;
JS Code
createRecord({
apiName:'Account',
{'Name':'Test Account'}
})
On the left, we have an Apex code which inserts an Account record and on the right we have the same example with createRecord function. Looking at this side-by-side comparison will help in better visualization.
The createRecord function needs to know which record we are creating thus we are passing the Object API name. It also needs to know the values to be assigned to the fields, thus the JSON structure.
Update Record using wire adapter & JS APIs in LWC
You can update records using updateRecord function provided by the lightning/uiRecordApi module. In this function, we need to pass the JSON structure of field API names and values to update and make sure the id of the record we want to edit is present. Check the code below for more details.
Syntax
Import the updateRecord adapter along with the ‘lwc’ module.
import { LightningElement } from 'lwc';
import { createRecord } from 'lightning/uiRecordApi';
Import References to the fields you want to update values for, also import the Object ID field (this is required for update).
import NAME_FIELD from '@salesforce/schema/Account.Name';
import ID_FIELD from '@salesforce/schema/Account.Id';
HTML Code
<template>
<lightning-input name="name" type="text" onchange={handleChange}></lightning-input>
<button onclick={updateAccount}>Create</button>
</template>
JS Code
import { LightningElement } from 'lwc';
import { createRecord } from 'lightning/uiRecordApi';
import NAME_FIELD from '@salesforce/schema/Account.Name';
import ID_FIELD from '@salesforce/schema/Account.Id';
export default class CreateRecordExample extends LightningElement {
name;
@api recordId
//gets called when value changed in lightning-input field
handleChange(event){
this.name = event.target.value;
}
//gets called on button click from html
createAccount() {
const fields = {};
fields[NAME_FIELD.fieldApiName] = this.name;
const recordInput = {
ID_FIELD.fieldApiName:this.recordId,
NAME_FIELD.fieldApiName:this.name
};
//call the updateRecord function by passing field value pair, which also includes record id
updateRecord(recordInput)
//gets called when record is successfully created
.then(account => {
//show a toast message in the UI on success
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Account created',
variant: 'success',
}),
);
})
//gets called when there is an error creating record
.catch(error => {
//show a toast message in the UI on error
this.dispatchEvent(
new ShowToastEvent({
title: 'Error creating record',
message: error.body.message,
variant: 'error',
}),
);
});
}
}
Fetch Record Data using wire adapters & JS APIs in LWC
Use getRecord wire adapter to fetch a record from Salesforce Database. The getRecord adapter returns an immutable stream of data, in order to make changes to this stream of data you need to make a copy of it.
This wire adapter is reactive in nature as it supports reactive variables (eg. ‘$recordId’). By reactive we mean if the value of the variable changes then the wire adapter is triggered to fetch the data again.
Note: The wire adapter might not make a network request to fetch the latest data if the data exists in the client cache. It the data in the cache is obsolete only then the network call is made.
Syntax
Import the @wire decorator and the getRecord adapter
import {wire} from ‘lwc’
import { getRecord,getFieldValue } from ‘lightning/uiRecordApi’
Import References to fields
import ACCOUNT_PHONE from '@salesforce/schema/Account.Phone';
import ACCOUNT_NAME from '@salesforce/schema/Account.Name';
import ACCOUNT_TYPE from '@salesforce/schema/Account.Type';
HTML Code
<template>
<h1 style="text-align:center;font-weight:bold">Using getRecord wire service</h1>
<div class="slds-m-around_medium">
<div style="display:flex"><div style="font-weight:bold">Account Name: </div><div>{accountName}</div></div>
<div style="display:flex"><div style="font-weight:bold">AccountType:</div> <div>{accounttype}</div></div>
<div style="display:flex"><div style="font-weight:bold">Phone:</div> <div>{phone}</div></div>
<button onclick={deleteAccount} data-accountid={accounId}>Delete</button>
</div>
</div>
</template>
JS Code
import ACCOUNT_PHONE from '@salesforce/schema/Account.Phone';
import ACCOUNT_NAME from '@salesforce/schema/Account.Name';
import ACCOUNT_TYPE from '@salesforce/schema/Account.Type';
export default class Wireservicesexample extends LightningElement {
@api recordId;
@api objectApiName;
accountName;
accountData;
accounttype;
accountId;
phone;
@wire(getRecord, {
recordId: "$recordId",
fields:[ACCOUNT_NAME,ACCOUNT_TYPE,ACCOUNT_PHONE]
})
record({ data, error }) {
if(data){
this.accountName = getFieldValue(data, ACCOUNT_NAME);
this.accounttype = getFieldValue(data, ACCOUNT_TYPE);
this.accountId = this.recordId;
this.phone = getFieldValue(data, ACCOUNT_NAME);
this.accountData = data;
} else if (error) {
console.log("error", error);
}
}
}
Explanation
Step 1: We start the code by importing the @wire decorator, getRecord and getFieldValue function.
Step 2: Next we get references to the fields (using @salesforce/schema/<ObjectApiName>.<FieldApiName>) we want to get while fetching the record. Think of it as the fields we mentioned in the SOQL query.
Example: SELECT Phone,Name,Type from Contact where Id='$recordId'
Step 3: Now use the @wire decorator with getRecord adapter and pass the recordId which you want to query with the fields, as an array of field references.
The response can be stored in a property or a function, in our example, we are using a function which acts as a callback. The function has two parameters data and error which are initialized when the getRecord call is complete.
The if block is executed if there are no errors while retrieving the data, you can then extract each field value using getFieldValue function.
You can then show the field values in the html field as per your UI/UX design.
Comparison for easy understanding.
On the left, we have a SOQL code which queries the Contact record with the fields mentioned and on the right we have the same example with getRecord wire adapter.
The getRecord adapter needs to know which record to fetch thus we are passing the recordId. It also needs to know which fields need to be returned thus the fields parameter.
Apex/SOQL Code
SELECT Phone,Name,Type from Contact where Id= <CONTACTID>
JS Code
@wire(getRecord, {
recordId:<CONTACTID>,
fields:[Phone,Name,Type]
})
Delete Salesforce Record using wire adapter & JS APIs in LWC
Use deleteRecord function to delete a record in Salesforce. To use this adapter you need to pass the recordId that need to be deleted and you are done.
Syntax
Import the deleteRecord function along with the ‘lwc’ module.
import { LightningElement } from 'lwc';
import { deleteRecord } from 'lightning/uiRecordApi';
HTML Code
<template>
<div class="slds-m-around_medium">
<div style="display:flex"><div style="font-weight:bold">Account Name: </div><div>{name}</div></div>
<div style="display:flex"><div style="font-weight:bold">AccountType:</div> <div>{accounttype}</div></div>
<div style="display:flex"><div style="font-weight:bold">Phone:</div> <div>{phone}</div></div>
<div style="display:flex"><div style="font-weight:bold">Website:</div> <div>{website}</div></div>
<button onclick={deleteAccount} data-accountid={accounId}>Delete</button>
</div>
</template>
JS Code
import { LightningElement } from 'lwc';
import { deleteRecord } from 'lightning/uiRecordApi';
export default class CreateRecordExample extends LightningElement {
//deleteAccount function is triggered when Delete button in the UI is clicked
deleteAccount(event){
//We can dynamically pass the record id in case of list of record by taking the below approach
//In HTML : <button data-accountId={accoundId}> Delete </button>
//In JS : let recordToDelete = event.currentTarget.dataset.accountId;
//Then use the recordToDelete as a paramter for deleteRecord
deleteRecord(recordId)
.then(() => {
//Toast message when the record is successfully deleted
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Record deleted',
variant: 'success'
})
);
})
.catch(error => {
//Toast message when there is an issue deleting the record
this.dispatchEvent(
new ShowToastEvent({
title: 'Error deleting record',
message: error.body.message,
variant: 'error'
})
);
});
}
}
Explanation:
Step 1: Import the deleteRecord function from the lightning/uiRecordApi module
Step 2: The HTML file renders a record that is fetched using getRecord @wire adapter or any other source(as discussed in getRecord section above). Then we have a button which calls a function in JS file when clicked.
Step 4: In the JS file deleteAccount function is called by clicking on the Delete button in the HTML. We are calling the deleteRecord by passing the this.recordId as a parameter.
Comparison for easy understanding.
Apex Code
Account accRec = [SELECT Id, Name from Account where Id=<AccountId>];
delete accRec
JS Code
deleteRecord(recordId)
On the left, we have an Apex code which deleted an Account record and on the right we have the same example with deleteRecord function.
The deleteRecord function needs the salesforce id of the record that needs to be deleted. The framework figures out the Object internally and deletes the correct record.
Note: When using wire adapters from lightning/ui*Api module it is recommended to import references to Objects and Fields. This tells Salesforce to verify objects and fields and prevent them from getting deleted. It also makes sure fields and objects are included in your change set and packages. Importing references also make sure your code works even when object and field label changes.
Note: All wire adapters in the lightning/ui*Api modules respect object CRUD rules, field-level security, and sharing. If a user doesn’t have access to a field, it isn’t included in the response.
Conclusion
The above-mentioned Wire Adapters & JS APIs in LWC provide a powerful feature to perform CRUD operations on Salesforce Object without calling the Apex Class.
These options provide great flexibility in terms of building a customized solution and complete control in terms of saving data.
One should always try to use the standard base components for their use-cases whenever possible as they provide greater flexibility, minimal code changes and low maintenance when working with Salesforce Data.
2 Comments