Skip to main content

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.

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. With lightning-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. When lightning-record-form doesn’t specify a recordId, it operates in edit 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 the success 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 the success event. handleSuccess is executed when the save operation succeeds.
  • Lines 11–17: We show a toast message by firing ShowToastEvent, in which event.detail.id is a reference to the id 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 the getFieldValue 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 the getRecord 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 and fields).
  • 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 in account.data. If the record retrieval fails, the error is stored in account.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 the recordId parameter as a string with a $ prefix, we make recordId reactive. Every time the value of recordId 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 the account 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 and error. 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 the data property and set the error property to undefined. Alternatively, if there is an error, we store the error in the error property and set the data 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 the Account.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 a lightning-button in the .html file (not shown). When handleButtonClick is invoked, it invokes the createRecord 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 (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 Trailhead Help.

  1. Click the Get Your Login Credentials tab and take note of your username.
  2. Click Reset My Password. This sends an email to the address associated with your username.
  3. Click the link in the email.
  4. 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. 

  1. Create a new project:
    1. Open Visual Studio Code.
    2. Open the command palette: Click View | Command Palette.
    3. In the command palette, select SFDX: Create Project.
      If you don’t see it in the list, type SFDX: Create Project and then press Enter.
    4. Accept the standard template.
    5. For the project name, enter workingWithDataInLWC and then press Enter.
    6. Select a location for the new project and then click Create Project.
  2. Authorize your Trailhead Playground:
    1. In the command palette, select (or enter) SFDX: Authorize an Org.
    2. Select Production: login.salesforce.com and press Enter.
    3. For alias, enter lwc_and_salesforce_data and then press Enter.
    4. Use your Trailhead Playground username and password to log in.
    5. When you are logged in to your Trailhead Playground, leave it open and return to Visual Studio Code.
  3. Create a Lightning web component:
    1. In the Explorer pane, right-click the lwc folder and select SFDX: Create Lightning Web Component.
    2. For the component name, enter accountCreator and press Enter.
    3. Press Enter again to accept the default directory.
  4. 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.
  5. 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>
  6. Save the three files: accountCreator.html, accountCreator.js, and accountCreator.js-meta.xml.
  7. Deploy the project files to your Trailhead Playground. (Right-click the accountCreator folder and select SFDX: Deploy Source to Org.)
  8. If your Trailhead Playground isn’t already open, open it. (In the command palette, select (or enter) SFDX: Open Default Org).
  9. In your Trailhead Playground, click Setup and then select Setup.
  10. In the Quick Find box, enter Lightning App Builder and then select Lightning App Builder.
  11. Create a Lightning page:
    1. Click New.
    2. Choose App Page and click Next.
    3. For label, enter Working with Data, and then click Next.
    4. For layout, choose Header and Left Sidebar.
    5. Click Finish.
  12. Drag the accountCreator component to the page sidebar.
  13. Save the page.
  14. Activate the page: Keep the default app name (Working with Data) and click Save.
  15. When prompted to add the page to the navigation menu, click Finish.
  16. 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

Keep learning for
free!
Sign up for an account to continue.
What’s in it for you?
  • Get personalized recommendations for your career goals
  • Practice your skills with hands-on challenges and quizzes
  • Track and share your progress with employers
  • Connect to mentorship and career opportunities