Base Lightning Components enable you to build Lightning applications with rich user interfaces faster and more easily. They also allow you to work with Salesforce data efficiently as these components are built on Lightning Data Service. One of the most used based components is lightning-datatable (see docs). The Lightning Datatable component enables you to work with multiple records and displays record data in rows and columns, and it supports various features, including inline editing, column formatting, custom datatypes, infinite scrolling, header actions, and more.

Note: If you want to create forms to work with a single record, you can use the lightning-record-*-form components (see docs).

In this post, we will cover three new datatable recipes that were recently added to the LWC Recipes sample app. These recipes demonstrate how to use inline editing and custom data types with the lightning-datatable component.

Datatable with inline editing

The first two recipes showcase the inline editing feature of the datatables. Each row of the datatable corresponds to a single record. The inline editing feature of the datatable enables users to update the field values of the records without navigating to the records. You can edit multiple records and save them, as illustrated below.

How does it work?

It takes just a few easy steps to implement inline editing of multiple records. You can load and cache the data in the client, enable inline editing for the required fields, display the data using the lightning-datatable component, and finally update the modified records by implementing a handler. Let’s explore each of these steps.

Load data

A list of contact records is loaded using SOQL in an Apex method, as shown below. The @AuraEnabled(cacheable=true) annotation exposes the method to Lightning components and caches the list of contact records on the client.

//ContactController.cls
public with sharing class ContactController {
    @AuraEnabled(cacheable=true)
    public static List<Contact> getContactList() {
        return [
            SELECT
                Id, Name, FirstName, LastName, Title, Phone, Email, Picture__c
            FROM Contact
            WHERE Picture__c != NULL
            WITH SECURITY_ENFORCED
            LIMIT 10
        ];
    }
}

Enable inline editing

You can enable inline editing for the rows by specifying which fields are editable, setting editable: true for the fields in the column definition. For example, First Name and Last Name fields can be set as editable, as shown below.

//datatableInlineEditWithUiApi.js
import { LightningElement, wire } from 'lwc';
import getContacts from '@salesforce/apex/ContactController.getContactList';
import ID_FIELD from '@salesforce/schema/Contact.Id';
import FIRSTNAME_FIELD from '@salesforce/schema/Contact.FirstName';
import LASTNAME_FIELD from '@salesforce/schema/Contact.LastName';

const COLS = [
    { label: 'First Name', fieldName: FIRSTNAME_FIELD.fieldApiName, editable: true},
    { label: 'Last Name', fieldName: LASTNAME_FIELD.fieldApiName, editable: true}
];

export default class DatatableInlineEditWithUiApi extends LightningElement {
    columns = COLS;
    draftValues = [];

    @wire(getContacts)
    contacts;
}

You can provision data from Apex using the wire service. Here you can see that we have imported the getContactList method as getContacts. We then wired it to the contacts property to provide the data.

Display the data

Once we have the data in the contacts property, we can use it in the lightning-datatable component to display it in the tabular form. The columns property supplies the columns information.

<!-- DatatableInlineEditWithUiApi.html --> <template if:true={contacts.data}> <lightning-datatable key-field="Id" data={contacts.data} columns={columns} onsave={handleSave} draft-values={draftValues} hide-checkbox-column > </lightning-datatable> </template>

When you edit a field in the datatable, the Save button appears, and the draftValues property holds the edited field values. You can implement a handler to process the draftValues when the Save button is pressed.

Update the modified records

The following two recipes showcase the inline editing feature of the datatable. All the above steps are common in both recipes, and they differ only in how we implement the update handler.

  • Datatable Inline Edit with UI API — This recipe uses the UI API to update the records
  • Datatable Inline Edit with Apex — This recipe uses Apex to update the records

Datatable Inline Edit with UI API recipe

The lightning/ui*Api wire adapters and functions (see docs) are built on top of the Lightning Data Service (LDS) and the User Interface API (UI API). These adapters and functions have simple syntax and are easy to use. You can import the required method in your javascript file and use it. The updateRecord method is imported in this recipe from the UI API.

//datatableInlineEditWithUiApi.js
import { updateRecord } from 'lightning/uiRecordApi';

Let’s take a look at the handler implementation.

//datatableInlineEditWithUiApi.js
async handleSave(event) {
        // Convert datatable draft values into record objects
        const records = event.detail.draftValues.slice().map((draftValue) => {
            const fields = Object.assign({}, draftValue);
            return { fields };
        });

        // Clear all datatable draft values
        this.draftValues = [];

        try {
            // Update all records in parallel thanks to the UI API
            const recordUpdatePromises = records.map((record) =>
                updateRecord(record)
            );
            await Promise.all(recordUpdatePromises);

            //Code to show a successful update message 

            // Display fresh data in the datatable
            await refreshApex(this.contacts);
        } catch (error) {
            // Handle error scenario
        }
    }

The event.detail.draftValues contains the edited field values of the modified records in JSON format. It is an array of record objects.

[
      {
        Id: '0031700000pJRRSAA4',
        FirstName: 'Amy',
        LastName: 'Taylor'
      },
      {
        Id: '0031700000pJRRTAA4',
        FirstName: 'Michael',
        LastName: 'Jones',
      }
]

The updateRecord() method expects the input in the following format. Hence, we need to convert the draftValues into record objects in the following format before invoking the method.

{
      fields: {
        Id: '0031700000pJRRTAA4',
        FirstName: 'Amy',
        LastName: 'Taylor',
      }
}

The updateRecord() method can process one record at a time, and it returns a promise. As we can invoke this method asynchronously, we can invoke it for all the records and await all the promises to finish before showing the success message. On successful completion of promises, invoke the refreshApex method to show fresh data in the datatable. The error can be caught and handled in the catch block. You can check out the complete code of datatableInlineEditWithUiApi in the LWC Recipes repository.

A caveat of this implementation is the updateRecord() method is invoked multiple times in its own transaction, hence the better way of doing this is updating the records by using Apex as implemented in the following recipe.

Datatable Inline Edit with Apex recipe

The modified records in the event.detail.draftValues can be updated in bulk using the update Data Manipulation Language(DML) operation in an Apex controller. Once the contacts are updated, you can display a success message and invoke the refreshApex() method to show fresh data in the datatable. The error can be caught and handled in the catch block.

//datatableInlineEditWithApex.js
async handleSave(event) {
    const updatedFields = event.detail.draftValues;

    try {
        // Pass edited fields to the updateContacts Apex controller
        await updateContacts({ contactsForUpdate: updatedFields });
        
       //Code to show a successful update message
        
       // Display fresh data in the datatable
        await refreshApex(this.contacts);
        
       // Clear all draft values in the datatable
        this.draftValues = [];
    } catch (error) {
        // Handle error scenario
    }
}

The updateContacts() method in the ContactController class checks the permissions and updates the records.

//ContactController.cls
public with sharing class ContactController {
@AuraEnabled
    public static void updateContacts(List<Contact> contactsForUpdate) {
        // Make sure we can update the database before trying to update
        if (!Schema.sObjectType.Contact.isUpdateable()) {
            throw new SecurityException(
                'Insufficient permissions to update contacts'
            );
        }
        update contactsForUpdate;
    }
}

You can check out the complete code of datatableInlineEditWithApex in the LWC Recipes repository.

Custom Data Type

The Custom Data Type allows you to create your own data types. You can implement a custom cell, such as a delete-a-row button or image. The lightning-datatable component supports both standard data types and custom data types; the lightning-datatable formats and displays the data based on the type you specify for the column. The standard data types include date, email, action, and button, which can be customized with the type attributes. In the following recipe, we will see how to use custom data type with the lightning-datatable component.

Datatable Custom Data Type recipe

We added a recipe that demonstrates how to use custom image type with the lightning-datatable component. We created Contact Picture as a custom data type.

How does it work?

A custom data type can be implemented in three easy steps. Create a Lightning Web Component and define your custom data types, create a custom data template and add the markup for your data type, and finally, implement your datatable with the newly defined custom data types. Let’s see how we implemented this in the Datatable Custom Data Type recipe.

Define Custom Data Types

You can create a Lightning Web Component and define your custom data types in its JavaScript file. We have created a customDataTypes component below.

//customDataTypes.js
import customPicture from './customPicture.html';

export default class CustomDataTypes extends LightningDatatable {
    static customTypes = {
        customPictureType: {
            template: customPicture,
            standardCellLayout: true,
            typeAttributes: ['pictureUrl']
        }
        // You can define more Custom Types
    };
}

You’ll notice that the CustomDataTypes class extends the LightningDatatable class. This is a unique scenario where you extend LightningDatatable only to create custom data types. It is important to note that extending any other class besides LightningElement to create a Lightning Web Component isn’t supported.

We have created a custom data type called customPictureType. The customPictureType object has three properties.

  • template — holds a reference to the custom data template, which has the markup for our data type. We will cover more about this in the next section.
  • standardCellLayout — is used to customize the look of lightning-datatable cells that use custom data types. There are two layouts: standard layout and bare layout. All the standard data types supported in lightning-datatable uses the standard layout. You can use any of these layouts for your custom cells. Here we are setting it to true, hence using a standard layout.
  • typeAttributes — holds a comma-separated list of attributes to be passed to the custom data template. Here we are passing pictureUrl to display the image. We will see how to use it in the next section.

Create a custom data template

You can add the markup of your custom data type to the Custom Data Template file, which is an HTML file. In this recipe, we want to display the contact’s profile picture in the cell. Hence, we have created a customPicture.html file and added it to the customDataTypes folder.

<!-- customPicture.html -->
<template>
    <img
        src={typeAttributes.pictureUrl}
       
        alt="Profile photo"
    />
</template>

The customPicture.html has a template that includes an image tag. The src attribute gets the pictureUrl from the typeAttributes, a property of the customPictureType defined in the previous section. The following section shows how to pass the pictureUrl value from the datatable JavaScript file.

Implement the datatable with custom data types

Once the custom data types are defined, you can implement your datatable with the custom data types. We have implemented a component called datatableCustomDatatype. Let’s look at its JavaScript file.

//datatableCustomDatatype.js
import { LightningElement, wire } from 'lwc';
import getContacts from '@salesforce/apex/ContactController.getContactList';

const COLS = [
    { label: 'First Name', fieldName: 'FirstName' },
    { label: 'Last Name', fieldName: 'LastName' }
    {
        label: 'Contact Picture',
        type: 'customPictureType',
        typeAttributes: {
            pictureUrl: { fieldName: 'Picture__c' }
        },
        cellAttributes: { alignment: 'center' }
    }
];

export default class DatatableCustomDataType extends LightningElement {
    columns = COLS;

    @wire(getContacts)
    contacts;
}

You can add a column to your datatable with the custom data type. In the above code, you can see that we have added a column labeled Contact Picture of customPictureType. You can also notice that we are assigning Picture__c field value to the pictureUrl type attribute. This value will be passed to our custom data type for rendering. We have also imported the getContactList method as getContacts and wired it to the contacts property.

You can use the c-custom-data-types tag to display the contacts in tabular form as the CustomDatatypes class extends the LightningDatatable class.

<!-- datatableCustomDatatype.html -->
<template if:true={contacts.data}>
    <c-custom-data-types
        key-field="Id"
        data={contacts.data}
        columns={columns}
        hide-checkbox-column="true"
    >
    </c-custom-data-types>
</template>

You can check the complete code of customDataTypes and datatableCustomDataType in the LWC Recipes repository.

Summary

Lightning-datatable (see docs) is one of the most powerful and widely used Lightning base components. Here we covered two critical scenarios with the implementation of three datatable recipes. We showed how to use the inline editing feature using the UI API and Apex, and how these implementations match and differ. We also showed how to use custom data types with the Lightning Datatable component. You can implement a variety of complex scenarios easily using Lightning Datatables. Checkout LWC Recipes and explore the three datatable recipes along with their tests. You can also explore other examples in LWC Recipes, tweak the code, re-use it, and also contribute.

Resources

About the author

Satya Sekhar Chegondi is a Senior Developer Advocate at Salesforce focusing on Lightning Web Components and developer tools. He is passionate about sharing his knowledge about all possible with the Salesforce Platform with various audiences in an understandable format. You can follow him on Twitter @SatyaSfdc.

Get the latest Salesforce Developer blog posts and podcast episodes via Slack or RSS.

Add to Slack Subscribe to RSS