Use Lightning Data Service to Work with Data
Learning Objectives
After completing this unit, you’ll be able to:
- Build solutions that include
lightning-record-*-form
base components.
- Use Lightning Data Service (LDS) wire adapters to read data.
- Use LDS functions to modify data.
If this is your first foray into Lightning Web Components, wait. Take a step back. Before you work through this module, make sure you complete the Lightning Web Components Basics module and the Learn to Work with JavaScript trail here on Trailhead. The work that you do here builds on the concepts and work that you do there.
Work with Data in Lightning Web Components
In Lightning web components, there are several ways to work with Salesforce data. Knowing which solution to use for a specific use case lets you write less code, simpler code, and more maintainable code. Using the best solution for each situation also improves the performance of your components and applications.
In this module you learn when and how to use different solutions. We review the easiest but least customizable options first. Later, we consider more complex and more customizable options.
Work with Data Using the Lightning Data Service
Lightning Data Service is the preferred (and easiest) way to work with Salesforce data. With Lightning Data Service, developers use JavaScript to connect components to Salesforce data.
Lightning Data Service also provides security by making server calls to secure User Interface API endpoints. Using a client-side shared cache across all components, Lightning Data Service maximizes performance. When a record is cached, it’s retrieved from the cache, eliminating unnecessary calls to the server.
Don’t rely on receiving data from a wire adapter at a specific point of the component lifecycle. Data from a wire adapter isn’t always accessible in lifecycle hooks like connectedCallback()
or renderedCallback()
. To learn more about the wire service data lifecycle, check out Understand the Wire Service.
Lightning Data Service maintains consistent, up-to-date data across multiple components and clients throughout the app lifecycle. If several components use Lightning Data Service to work with a record, and one of them updates the record, the other components automatically reflect that update.
In the following sections, we highlight different ways to work with Salesforce data using the Lightning Data Service.
Read or Modify Data with Record Form Base Components
The easiest way to work with single records in Lightning web components is to use the lightning-record-*-form
components. These base components use Lightning Data Service behind the scenes and inherit its caching and synchronization capabilities. Each base component gives you different features and levels of customization.
-
lightning-record-form
base component is the simplest one. Withlightning-record-form
, you can specify a layout and allow admins to configure form fields declaratively. You can also specify an ordered list of fields to programmatically define what’s displayed.lightning-record-form
allows you to view and edit records.
-
lightning-record-view-form
base component allows you to view records.
-
lightning-record-edit-form
base component allows you to edit records.
Choose lightning-record-view-form
or lightning-record-edit-form
when you need to customize the form layout, prepopulate field values, or change how record data is rendered.
Here’s an example that uses lightning-record-form
to create accounts.
accountCreator.html
<template> <lightning-card> <lightning-record-form object-api-name={objectApiName} fields={fields} onsuccess={handleSuccess}> </lightning-record-form> </lightning-card> </template>
accountCreator.js
import { LightningElement } from 'lwc'; import { ShowToastEvent } from 'lightning/platformShowToastEvent'; import ACCOUNT_OBJECT from '@salesforce/schema/Account'; import NAME_FIELD from '@salesforce/schema/Account.Name'; import REVENUE_FIELD from '@salesforce/schema/Account.AnnualRevenue'; import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry'; export default class AccountCreator extends LightningElement { objectApiName = ACCOUNT_OBJECT; fields = [NAME_FIELD, REVENUE_FIELD, INDUSTRY_FIELD]; handleSuccess(event) { const toastEvent = new ShowToastEvent({ title: "Account created", message: "Record ID: " + event.detail.id, variant: "success" }); this.dispatchEvent(toastEvent); } }
Code highlights:
accountCreator.html
- Line 3: By using
lightning-record-form
in the markup, we get all of the security and performance benefits that Lightning Data Service provides. Whenlightning-record-form
doesn’t specify arecordId
, it operates inedit
mode, and creates a record on submit.
- Line 4: Binding the
object-api-name
property indicates the kind of object to load.
- Line 5: Binding the
fields
property indicates the fields to show in the form.
- Line 6: We set
handleSuccess
as the handler for thesuccess
event.
accountCreator.js
- Lines 3–6: At the beginning of the file, we import references to the Account object and its fields. Referencing objects and fields in this way ensures referential integrity. Salesforce verifies that the object and fields exist, prevents them from being deleted, and ensures that they are included in change sets and packages that reference the component. Importing object and field references ensures that your component code still works if the object or fields are renamed.
- Line 10: We define the
handleSuccess
event handler for thesuccess
event.handleSuccess
is executed when the save operation succeeds.
- Lines 11–17: We show a toast message by firing
ShowToastEvent
, in whichevent.detail.id
is a reference to theid
property of the newly created record.
If you need more customization than the lightning-record-*-form
components provide, you can invoke Lightning Data Service directly by using a wire adapter or JavaScript function.
Read Data with LDS Wire Adapters
LDS wire adapters are another way to work with Salesforce data. Use a wire adapter to read Salesforce data (records) and metadata (layout details, fields on an object, and so on). To use them, decorate a property or function with @wire
and specify the wire adapter.
LDS wire adapters check the LDS cache first, and request data from the server only as needed. Adapters react to change and refresh data accordingly. For example, when the parameter value changes, or other components modify data in the Lightning Data Service cache, an adapter provisions the new data to the wired property or function.
Let’s review an example that uses the getRecord wire adapter.
wireGetRecordProperty.js
import { LightningElement, api, wire } from 'lwc'; import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; import ACCOUNT_NAME_FIELD from '@salesforce/schema/Account.Name'; export default class WireGetRecordProperty extends LightningElement { @api recordId; @wire(getRecord, { recordId: '$recordId', fields: [ACCOUNT_NAME_FIELD] }) account; get name() { return getFieldValue(this.account.data, ACCOUNT_NAME_FIELD); } }
Code highlights:
- Line 2: We import the
getRecord
wire adapter and thegetFieldValue
function.
- Line 3: Like we did in the accountCreator example, we import a reference to the
Account.Name
field. (In line 6, we use this to tell thegetRecord
wire adapter which fields to retrieve.)
- Line 5: When the wireGetRecordProperty component is placed on a record page,
@api recordId
lets the parent component (the FlexiPage) pass the Id of the current record to the component.
- Line 6: To wire the account property, we apply the
@wire
decorator and specify the wire adapter to call (getRecord
), and the parameters that the adapter needs (recordId
andfields
).
- Line 7: The wire adapter provisions a stream of values to the
account
property, which will be set multiple times. If a record is retrieved, it’s stored inaccount.data
. If the record retrieval fails, the error is stored inaccount.error
.
- Lines 6–7: The first time a value is assigned to the
recordId
property, the wire adapter gets the data from the server and stores it in the LDS cache for future access. By passing therecordId
parameter as a string with a$
prefix, we makerecordId
reactive. Every time the value ofrecordId
changes, the wire adapter gets new data, either from the cache or from the server. If another component modifies the cached record, the wire adapter provisions the record’s new value to theaccount
property.
- Lines 8-10: We define a getter for the name property. The getFieldValue function provides access to the field values from the returned data.
In this example, the name property can be retrieved in the HTML file like this:
wireGetRecordProperty.html
<template> Account Name: {name} </template>
wireGetRecordProperty is an example of decorating a property. We can decorate a function in the same way. This is useful when you want to execute some logic over the returned records. Here’s the previous example (wireGetRecordProperty), reworked to wire a function (wiredAccount
) instead of a property.
wireGetRecordFunction.js
import { LightningElement, api, wire } from 'lwc'; import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; import ACCOUNT_NAME_FIELD from '@salesforce/schema/Account.Name'; export default class WireGetRecord extends LightningElement { @api recordId; data; error; @wire(getRecord, { recordId: '$recordId', fields: [ACCOUNT_NAME_FIELD] }) wiredAccount({data, error}) { console.log('Execute logic each time a new value is provisioned'); if (data) { this.data = data; this.error = undefined; } else if (error) { this.error = error; this.data = undefined; } } get name() { return getFieldValue(this.data, ACCOUNT_NAME_FIELD); } }
Code highlights:
- Lines 8–9: Instead of decorating a property, we decorate the
wiredAccount
function. The function receives, as a parameter, an object that has two attributes:data
anderror
. We use object ES6 destructuring to unpack the object attributes.
- Lines 11–17: Because LDS wire adapters provision not a single value, but a stream of values, the
wiredAccount
function can be invoked multiple times. As a result, a wired function must reset states that it influences. So here, in lines 11–17, if the wire adapter provisions new data, we store the data in thedata
property and set theerror
property to undefined. Alternatively, if there is an error, we store the error in theerror
property and set thedata
property to undefined.
In this example, we can access the name
property the same way we accessed it in the previous example.
Modify Data with LDS Functions
LDS wire adapters are great for reading data, but to create, update, or delete records, you need an LDS function. Note that while wire adapters are invoked by the Lightning Web Components engine, you invoke functions imperatively. LDS functions notify the LDS cache when records are created, updated, or deleted. Consider this example, which uses the createRecord LDS function to create an account record.
ldsCreateRecord.js
import { LightningElement} from 'lwc'; import { createRecord } from 'lightning/uiRecordApi'; import ACCOUNT_OBJECT from '@salesforce/schema/Account'; import ACCOUNT_NAME_FIELD from '@salesforce/schema/Account.Name'; export default class LdsCreateRecord extends LightningElement { handleButtonClick() { const recordInput = { apiName: ACCOUNT_OBJECT.objectApiName, fields: { [ACCOUNT_NAME_FIELD.fieldApiName] : 'ACME' } }; createRecord(recordInput) .then(account => { // code to execute if create operation is successful }) .catch(error => { // code to execute if create operation is not successful }); } }
Code highlights:
- Line 2: We import the
createRecord
LDS function.
- Lines 3–4: We import the
Account
object and theAccount.Name
field (as we did in the previous examples) to ensure referential integrity.
- Line 6: We define the
handleButtonClick
method as an event handler. It responds to the event that occurs when a user clicks alightning-button
in the .html file (not shown). WhenhandleButtonClick
is invoked, it invokes thecreateRecord
function imperatively.
- Line 10: Our event handler passes a string for the
Account.Name
field, which the adapter needs to create a new account.
- Line 13: When we invoke an LDS function imperatively, it returns a promise (a JavaScript object that simplifies performing asynchronous calls).
- Lines 14–16: In the
then
method, we define what happens if the account is created successfully.
- Lines 17–19: In the
catch
method, we define what happens if the account creation fails.
Note: LDS functions allow you to work with single records only. Although you can use several functions in the same component (to create two different kinds of records in the same operation, for example), each function runs on its own independent transaction. Therefore, there is no common rollback logic. If you need a combined DML operation to be transactional, consider using Apex.
To learn more about LDS wire adapters and functions, and how to use them, visit the Lightning Web Components Developer Guide and the Salesforce Developers Blog.
Deploy a Lightning Web Component That Creates Accounts
Now that we’ve reviewed different ways to work with Lightning Data Service, let’s work through an example.
Before You Begin
We assume that you have your Salesforce DX development environment set up, and you’re comfortable using it to create Lightning web components and deploy them to an org. If you’re not familiar with this process yet, complete the Quick Start: Lightning Web Components project.
Create a New Trailhead Playground
For this project, you need to create a new Trailhead Playground. Scroll to the bottom of this page, click the down arrow next to Launch, and select Create a Trailhead Playground. It typically takes 3–4 minutes to create a new Trailhead Playground.
Note: Yes, we really mean a brand-new Trailhead playground! If you use an existing org or playground, you can run into problems completing the challenges.
Get Your Trailhead Playground Username and Password
Go to your Trailhead Playground. (If it’s not already open, scroll to the bottom of this page and click Launch.) If you see a tab in your org labeled Get Your Login Credentials, great! Skip ahead to step 1.
Otherwise, from the App Launcher (), find and open Playground Starter and follow the steps. If you don’t see the Playground Starter app, check out Find the Username and Password for Your Trailhead Playground on Salesforce Help.
- Click the Get Your Login Credentials tab and take note of your username.
- Click Reset My Password. This sends an email to the address associated with your username.
- Click the link in the email.
- Enter a new password, confirm it, and click Change Password.
Ready to get hands-on? Let’s go.
In this exercise, you add a Lightning web component to your project and then deploy it to your Trailhead Playground.
- Create a new project:
- Open Visual Studio Code.
- Open the command palette: Click View | Command Palette.
- In the command palette, select SFDX: Create Project.
If you don’t see it in the list, typeSFDX: Create Project
and then press Enter.
- Accept the standard template.
- For the project name, enter
workingWithDataInLWC
and then press Enter.
- Select a location for the new project and then click Create Project.
- Authorize your Trailhead Playground:
- In the command palette, select (or enter) SFDX: Authorize an Org.
- Select Production: login.salesforce.com and press Enter.
- For alias, enter
lwc_and_salesforce_data
and then press Enter.
- Use your Trailhead Playground username and password to log in.
- When you are logged in to your Trailhead Playground, leave it open and return to Visual Studio Code.
- Create a Lightning web component:
- In the Explorer pane, right-click the lwc folder and select SFDX: Create Lightning Web Component.
- For the component name, enter
accountCreator
and press Enter.
- Press Enter again to accept the default directory.
- Replace the contents of your accountCreator.html and accountCreator.js files with the code provided in the Read or Modify Data with Record Form Base Components section earlier in this unit.
- To make this component available on app pages in an org, replace the contents of your accountCreator.js-meta.xml file with this code:
<?xml version="1.0" encoding="UTF-8"?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>48.0</apiVersion> <isExposed>true</isExposed> <targets> <target>lightning__AppPage</target> </targets> </LightningComponentBundle>
- Save the three files: accountCreator.html, accountCreator.js, and accountCreator.js-meta.xml.
- Deploy the project files to your Trailhead Playground. (Right-click the accountCreator folder and select SFDX: Deploy Source to Org.)
- If your Trailhead Playground isn’t already open, open it. (In the command palette, select (or enter) SFDX: Open Default Org).
- In your Trailhead Playground, click and then select Setup.
- In the Quick Find box, enter
Lightning App Builder
and then select Lightning App Builder.
- Create a Lightning page:
- Click New.
- Choose App Page and click Next.
- For label, enter
Working with Data
, and then click Next.
- For layout, choose Header and Left Sidebar.
- Click Done.
- Drag the accountCreator component to the page sidebar.
- Save the page.
- Activate the page: Keep the default app name (Working with Data) and click Save.
- When prompted to add the page to the navigation menu, click Finish.
- Open the new page: In the App Launcher search, enter
work
, and then select Working with Data.
That’s it. You have a Lightning web component that uses lightning-record-form
to create account records on the Working with Data page. Using Lightning Data Service is one way to work with Salesforce data in Lightning web components. In the next unit, you learn how to use Apex to work with data.
Resources
- Lightning Web Components Developer Guide: Lightning Data Service
- Lightning Web Components Developer Guide: Work with Records Using Base Components
- Lightning Web Components Developer Guide: Use the Wire Service to Get Data
- Blog: Caching and Synchronizing Component Data with Lightning Data Service