Salesforce provides a robust platform for managing data and automating business processes, but there are certain limitations when it comes to inline editing of lookup fields. Out of the box, Salesforce does not support inline editing for lookup fields in standard Lightning components like the lightning-data table. However, with some creativity and development skills, you can implement workarounds to achieve inline editing for lookup fields. This blog post will explore a workaround to make this happen.
Understanding the Challenge
Before we dive into the solution, let's understand why inline editing for lookup fields is a challenge. Since lookup fields in Salesforce are typically references to related records, editing them requires you to select a new record from a lookup dialog.
Custom Lookup Editing in Lightning Datatable
In Salesforce, working with lookup fields can be complex, as they typically display record IDs or reference information. This code addresses this challenge by providing a custom solution to enhance the user experience when dealing with lookup fields in LWC datatables. It introduces a custom LWC component, CustomDatatable, which extends the lightning/datatable component. The custom component defines the lookupColumn custom data type, which is optimized for handling lookup fields. Let's break down the implementation step by step:
1. Extending Lightning Datatable
First, we create a custom component called customDatatable. It extends the functionality of the standard lightning datatable by adding a custom data type called lookupColumn
import LightningDatatable from 'lightning/datatable';
import lookupColumn from './lookupColumn.html';
export default class CustomDatatable extends LightningDatatable {
static customTypes = {
lookupColumn: {
template: lookupColumn,
standardCellLayout: true,
typeAttributes: ['value', 'fieldName', 'object', 'context', 'name', 'fields', 'target']
}
};
}
2. Custom Lookup Editing Template
This template is used to render a custom data type, lookupColumn, within a Lightning Web Component. It uses the <c-lookup-column> component to handle the rendering and styling of the cell for this custom data type. The data for the custom cell is provided through the typeAttributes object, and the attributes of the <c-lookup-column> component are dynamically populated with these values.
<template>
<c-lookup-column value={typeAttributes.value} field-name={typeAttributes.fieldName}
object={typeAttributes.object} context={typeAttributes.context} name={typeAttributes.name}
fields={typeAttributes.fields} target={typeAttributes.target}>
</c-lookup-column>
</template>
3. Implementing Custom Lookup Editing
The lookupColumn custom data type has specific type attributes that allow you to pass values and configuration options when using it in the datatable. These attributes include value, fieldName, object, context, name, fields, and target.
The "lookupColumn" Lightning Web Component is designed to handle the display and editing of a lookup field for a specific object in Salesforce. It offers two distinct views: an editable input field for modifying the lookup value and a read-only view with a formatted URL and an "Edit" button. Switching between the edit mode and view mode is based on the showLookup property. Dispatching a custom event to notify the parent component when the lookup value is changed.
<template>
<div class="lookupSection" id="lookup">
<div if:true={showLookup} class="lookup-section">
<div tabindex="0" class="container">
<lightning-record-edit-form object-api-name={object}>
<lightning-input-field class="slds-popover slds-popover_edit slds-popover__body" field-name={fieldName} value={value} variant="label-hidden" onchange={handleChange} data-id="input"></lightning-input-field>
</lightning-record-edit-form>
<div if:false={showLookup} class="slds-table_edit_container slds-is-relative">
<span class="slds-grid slds-grid_align-spread slds-cell-edit slds-align_absolute-center">
<span class="slds-truncate" title={lookupName}>
<lightning-formatted-url value={lookupValue} label={lookupName} target={target}></lightning-formatted-url>
</span>
<button data-id={context} class="slds-button slds-button_icon slds-cell-edit__button slds-m-left_x-small" tabindex="-1" title="Edit" onclick={handleClick}>
<svg class="slds-button__icon slds-button__icon_hint slds-button__icon_lock slds-button__icon_small slds-button__icon_edit slds-icon slds-icon-text-default slds-icon_xx-small" aria-hidden="true">
<use xlink:href="/_slds/icons/utility-sprite/svg/symbols.svg?cache=9.37.1#edit"></use>
</svg>
<span class="slds-assistive-text">Edit</span>
</button>
</span>
</div>
</div>
</template>
4. Usage in Lightning Component
In Lightning Web Component (LWC) called "DemoPage," which is used to display and manage opportunities. It uses a customized data table (c-custom-datatable) to display opportunity records. The "Account Name" field is a lookup field. The LWC custom data type "lookupColumn" is used to handle lookup fields effectively.
<c-custom-datatable class="myTable" key-field="Id" data={visibleRecords} columns={columns} onsave={handleInlineEditSave} onvalueselect={handleSelection} draft-values={draftValues} oncellchange={handleCellChange} onlookupchanged={lookupChanged} ></c-custom-datatable>
lookupChanged(event) {
event.stopPropagation();
let dataRecieved = event.detail.data;
let accountIdVal = dataRecieved.value != undefined ? dataRecieved.value : null;
let updatedItem = { Id: dataRecieved.context, AccountId: accountIdVal };
this.updateDraftValues(updatedItem);
this.updateDataValues(updatedItem);
}
Updating Draft Values
Now, let's explore the updateDraftValues method. This method plays a crucial role in managing and tracking changes made to the draft (unsaved) values in the Lightning data table. It ensures that the changes are properly reflected and followed.
updateDraftValues(updateItem) {
let draftValueChanged = false;
let copyDraftValues = [...this.draftValues];
copyDraftValues.forEach(item => {
if (item.Id === updateItem.Id) {
for (let field in updateItem) {
item[field] = updateItem[field];
}
draftValueChanged = true;
}
});
if (draftValueChanged) {
this.draftValues = [...copyDraftValues];
} else {
this.draftValues = [...copyDraftValues, updateItem];
}
}
It receives an updateItem object, which typically represents the changes made to a record in the data table.
It creates a copy of the current draftValues array to prevent direct mutations.
It iterates through the copy of draftValues to find the item that matches the ID of the updateItem.
If a matching item is found, it updates the fields in that item with the new values from updateItem.
If no matching item is found, it adds the updateItem to the draftValues array.
The draftValueChanged flag is used to track whether changes were made, and if so, it updates the draftValues array accordingly.
Handling Cell Changes
Within our demoPage Lightning component, we have a method called handleCellChange. This method plays a crucial role in managing changes made to cell values within the data table. When a user makes changes to a cell, such as modifying the phone number or email address, these changes are captured in the draftValues array.
The handleCellChange method iterates through the draftValues array and ensures that the changes are properly tracked and reflected in the UI. It calls the updateDraftValues method to update the draftValues array, which represents the pending changes that need to be saved.
handleCellChange(event) {
let draftValues = event.detail.draftValues;
draftValues.forEach(element => {
this.updateDraftValues(element);
});
}
Updating and Reloading Leads
The heart of this custom lookup editing solution is the handleInlineEditSave method. This method is responsible for updating the changed values in the records and then refreshing the datatable to reflect the changes.
Here's a high-level overview of how it works:
It extracts the changes from draftValues and prepares them for updating records.
It uses lightning/uiRecordApi to update the records asynchronously.
If the updates are successful, it displays a success message using
If the updates are successful, it displays a success message using lightning/platformShowToastEvent.
Finally, it calls refreshApex to refresh the data in the datatable, ensuring that the latest values are displayed.
async handleInlineEditSave(event) {
const draftValues = event.detail.draftValues;
if (draftValues.length === 0) {
return;
}
this.draftValues = [];
const records = draftValues.map(draftValue => ({ fields: { ...draftValue } }));
try {
const recordUpdatePromises = records.map((record) =>
updateRecord(record)
);
await Promise.all(recordUpdatePromises);
this.createAndDispatchToast(CUSTOM_SUCCESS_TITLE_LABEL, CUSTOM_SUCCESS_MESSAGE_LABEL, CUSTOM_SUCCESS_VARIANT_LABEL);
refreshApex(this.wiredOpportunitiesResult);
} catch (error) {
this.createAndDispatchToast(CUSTOM_ERROR_TITLE_LABEL, CUSTOM_ERROR_MESSAGE_LABEL, CUSTOM_ERROR_VARIANT_LABEL);
}
}
Apex Controller and Data Retrieval
To populate the datatable and save changes, you'll need an Apex controller. In this example, we have an Apex controller named OpportunityController that retrieves and updates Opportunity records.
Conclusion
In conclusion, our custom lookup field editing solution for Lightning Web Components effectively overcomes Salesforce's limitations by providing user-friendly inline editing for lookup fields. This solution empowers developers to enhance data management and improve the user experience, bridging a crucial gap in Salesforce's capabilities.
If you'd like to see the code and resources used in this project, you can access the repository on GitHub.To access the AVENOIRBLOGS repository, click here. Feel free to explore the code and use it as a reference for your own projects.
Happy Coding! You can leave a comment to help me understand how the blog helped you. If you need further assistance, please contact us. You can click "Reach Us" on the website and share the issue with me.
Blog Credit:
P. Ahuja
Salesforce Developer
Avenoir Technologies Pvt. Ltd.
Reach us: team@avenoir.ai
Are you in need of Salesforce Developers?