Display Data in a Table with Inline Editing
To display Salesforce data in a table, use the lightning-datatable
component. The component supports
inline editing, which enables users to update a field value without navigating to the
record.
To load a list of records, use the getListUi (Deprecated)
wire adapter or use SOQL in an Apex
method. See Data Guidelines.
This example uses SOQL in an Apex method to load contacts on an account record.
public with sharing class ContactController {
@AuraEnabled(cacheable=true)
public static List<Contact> getContacts(String accId) {
return [
SELECT AccountId, Id, FirstName, LastName, Title, Phone, Email
FROM Contact
WHERE AccountId = :accId
WITH SECURITY_ENFORCED
];
}
}
The @AuraEnabled(cacheable=true)
annotation
exposes the method to Lightning components and caches the list of contacts on the
client. The accId
parameter filters the contacts
for the given account record.
If the Apex method returns data, the HTML template displays the lightning-datatable
component with editable first name and last name
fields (1). When you edit a field, the Save button appears, and you can click it
to update the contact record. Updating a contact record successfully also updates the
record data in the related lists (2), and
other components on the page that are managed by Lightning Data Service.
To enable inline editing, configure the lightning-datatable
component as shown in the following
apexContactsForAccount template.
<!-- apexContactsForAccount.html -->
<template>
<lightning-card title="Datatable Example" icon-name="custom:custom63">
<div class="slds-m-around_medium">
<template if:true={contacts.data}>
<lightning-datatable
key-field="Id"
data={contacts.data}
columns={columns}
onsave={handleSave}
draft-values={draftValues}>
</lightning-datatable>
</template>
<template if:true={contacts.error}>
<!-- handle Apex error -->
</template>
</div>
</lightning-card>
</template>
The required key-field
attribute associates each
row with a contact record. The data
attribute
holds the data retrieved through the wire service from either an Apex method or a
wire adapter. The columns
attribute assigns a
record field to each column and customizes the behavior of the columns. When a user
edits a cell, the updated value is stored in draft-values
.
Clicking the Save button triggers the save
event. Use the onsave
event handler to persist
changes in the datatable. In the example, the onsave
event handler calls updateRecord(recordInput, clientOptions)
to save record
changes.
lightning-datatable
.Enable Inline Editing for a Datatable
A row of data corresponds to a single record and each column displays the value of
one of that record’s fields. To enable inline editing, specify which fields are
editable by setting editable: true
in the
column definition. In this example, the First Name and Last Name fields are
editable. Since the Name field on contacts is a compound field,
you must use the First Name and Last Name fields separately.
// apexContactsForAccount.js
import { LightningElement, wire, api } from 'lwc';
import getContacts from '@salesforce/apex/ContactController.getContactList';
import { refreshApex } from '@salesforce/apex';
import { updateRecord } from 'lightning/uiRecordApi';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import FIRSTNAME_FIELD from '@salesforce/schema/Contact.FirstName';
import LASTNAME_FIELD from '@salesforce/schema/Contact.LastName';
import TITLE_FIELD from '@salesforce/schema/Contact.Title';
import PHONE_FIELD from '@salesforce/schema/Contact.Phone';
import EMAIL_FIELD from '@salesforce/schema/Contact.Email';
import ID_FIELD from '@salesforce/schema/Contact.Id';
const COLS = [
{
label: 'First Name',
fieldName: FIRSTNAME_FIELD.fieldApiName,
editable: true
},
{
label: 'Last Name',
fieldName: LASTNAME_FIELD.fieldApiName,
editable: true
},
{ label: 'Title', fieldName: TITLE_FIELD.fieldApiName, editable: true },
{
label: 'Phone',
fieldName: PHONE_FIELD.fieldApiName,
type: 'phone',
editable: true
},
{
label: 'Email',
fieldName: EMAIL_FIELD.fieldApiName,
type: 'email',
editable: true
}
];
export default class DatatableInlineEditWithUiApi extends LightningElement {
@api recordId;
columns = COLS;
draftValues = [];
@wire(getContacts, { accId: '$recordId' })
contacts;
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);
// Report success with a toast
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Contacts updated',
variant: 'success'
})
);
// Display fresh data in the datatable
await refreshApex(this.contacts);
} catch (error) {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error updating or reloading contacts',
message: error.body.message,
variant: 'error'
})
);
}
}
}
@wire(getContacts)
provisions data to
contacts.data
and the record Id to
accId
.
When you edit fields, event.detail.draftValues
stores the edited field values and the record
Id
as an array of objects.
[
{
"FirstName": "Sean",
"Id": "003R0000002J2wHIAS"
},
{
"FirstName": "Jack",
"Id": "003R0000002J2wIIAS"
}
]
When you press the Tab key or click outside the cell after making changes, the
datatable footer appears with the Cancel and Save buttons. To hide the
datatable footer, clear the draftValues
property. The onsave
event handler clears draftValues
after copying the values into a
record object.
Call updateRecord(recordInput, clientOptions)
to save the
new field values to the records.
updateRecord()
expects a single record only.
Pass in a recordInput
object for each
record whose fields you’re updating. In this example, the record
parameter contains an object with the
updated fields for multiple records. To update multiple records simultaneously, pass
the parameter to updateRecord()
for
processing.
After a successful save, the onsave
event handler
dispatches the ShowToastEvent
event to
display a success toast message.
After a record is updated, refreshApex(this.contacts)
refreshes the list of contacts from the
Apex method so that the datatable always presents the latest data.
Enable Inline Editing Using Apex
For bulk record updates, pass your record changes to an Apex controller that calls an
update
Data Manipulation Language (DML)
operation. In this example, the edited field values are passed to the updateContacts
Apex controller. Since the
records are updated by Apex, you must notify Lightning Data Service (LDS) using the
getRecordNotifyChange(recordIds)
function so
that the Lightning Data Service cache and wires are refreshed.
In the apexContactsForAccount.js file you created in the
previous example, import the Apex controller and the getRecordNotifyChange
function.
import updateContacts from '@salesforce/apex/ContactController.updateContacts';
import { getRecordNotifyChange } from 'lightning/uiRecordApi';
Update the handleSave()
function to handle
the edited values. To ensure that getRecordNotifyChange()
is called after the record is updated via
Apex, use the async
/await
pattern or a Promise chain. This example
uses async
/await
.
async handleSave(event) {
const updatedFields = event.detail.draftValues;
// Prepare the record IDs for getRecordNotifyChange()
const notifyChangeIds = updatedFields.map(row => { return { "recordId": row.Id } });
try {
// Pass edited fields to the updateContacts Apex controller
const result = await updateContacts({data: updatedFields});
console.log(JSON.stringify("Apex update result: "+ result));
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Contact updated',
variant: 'success'
})
);
// Refresh LDS cache and wires
getRecordNotifyChange(notifyChangeIds);
// Display fresh data in the datatable
await refreshApex(this.contacts);
// Clear all draft values in the datatable
this.draftValues = [];
}
} catch(error) {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error updating or refreshing records',
message: error.body.message,
variant: 'error'
})
);
};
}
The updateContacts
Apex controller
deserializes the JSON string containing the updated fields into a Contact object. It
updates the changed records using the update
DML operation.
@AuraEnabled
public static string updateContacts(Object data) {
List<Contact> contactsForUpdate = (List<Contact>) JSON.deserialize(
JSON.serialize(data),
List<Contact>.class
);
try {
update contactsForUpdate;
return 'Success: contacts updated successfully';
}
catch (Exception e) {
return 'The following exception has occurred: ' + e.getMessage();
}
}
No comments:
Post a Comment