Hello Guys,
Today in this post, we will learn about the Custom Table Of Inline Editing In Lwc. Guys, we created a custom table and we are displaying an account table with inline edit. The code is pretty simple and everything is explained in code by comment. we don't need to explain everything because code is written in simple way and we kept in mind the best practice.
Let's Start
Step 1 : InlineEditingInLwcCtrl
public with sharing class InlineEditingInLwcCtrl {
/* ############# Fatch Accounts ################ */
(cacheable = true)
public static list < Account > fetchAccounts() {
try {
return [SELECT Id, Name, AccountNumber, Industry, Type, Active__c, Phone FROM Account Limit 10];
} catch (Exception e) {
throw new AuraHandledException(e.getMessage());
}
}
/* ############# Update Accounts ################ */
public static void updateAccounts(list < Account > updateRecords) {
try {
update updateRecords;
} catch (Exception e) {
throw new AuraHandledException(e.getMessage());
}
}
}
Step 2 : InlineEditingInLwc.Html
<template>
<lightning-card>
<!-- #################### Description ################## -->
<div>
<h1 style="text-align:center;font-weight:bold;font-size:18px;">Inline Editing In LWC
</h1>
<h1 style="text-align:center;padding-bottom:12px;">By Sfdcfamily.blogspot.com
</h1>
</div>
<!-- ######################################## -->
<!-- #################### Loading Spinner #################### -->
<template if:true={isLoading}>
<lightning-spinner variant="brand" size="small">
</lightning-spinner>
</template>
<!-- ######################################## -->
<lightning-layout>
<lightning-layout-item size="12">
<!-- #################### Custom Table Start #################### -->
<table class="slds-table slds-table_cell-buffer slds-table_bordered">
<!-- #################### Table Header Start #################### -->
<thead>
<tr class="slds-line-height_reset slds-gutters">
<th class="slds-col" scope="col">
<div class="slds-truncate c__headerWidth" title="Account Name">Account Name
</div>
</th>
<th class="slds-col" scope="col">
<div class="slds-truncate">Account Number
</div>
</th>
<th class="slds-col" scope="col">
<div class="slds-truncate">Type
</div>
</th>
<th class="slds-col" scope="col">
<div class="slds-truncate">Industry
</div>
</th>
<th class="slds-col" scope="col">
<div class="slds-truncate">Phone
</div>
</th>
<th class="slds-col" scope="col">
<div class="slds-truncate">Active
</div>
</th>
</tr>
</thead>
<!-- #################### Table Header End #################### -->
<!-- #################### Table Body Start #################### -->
<tbody>
<template for:each={lstRecords} for:item="rec" for:index="indx">
<tr class="slds-hint-parent slds-wrap" key={rec.Id}>
<!--#################### Name Td Start #################### -->
<td role="" onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Name" data-recid={rec.Id} data-rowindx={indx}
class={rec.manageEdit.c_Name}>
<!--#################### Viem Mode #################### -->
<template if:false={rec.manageEdit.Name}>
<span class="slds-grid slds-grid--align-spread forceInlineEditCell"
onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Name" data-recid={rec.Id} data-rowindx={indx}>
<span onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Name" data-recid={rec.Id} data-rowindx={indx}
class="slds-truncate" title={rec.Name}>{rec.Name}
</span>
<span class={rec.displayEditIcon.Name}>
<button data-colname="Name" onclick={handleEdit} data-recid={rec.Id}
data-rowindx={indx}
class="slds-button slds-button_icon slds-cell-edit__button c__editButtonCss"
tabindex="0">
<lightning-icon data-colname="Name" data-recid={rec.Id}
data-rowindx={indx} size="xx-small" icon-name="utility:edit"
alternative-text="editIcon">
</lightning-icon>
</button>
</span>
</span>
</template>
<!-- ################################ -->
<!--#################### Edit Mode #################### -->
<template if:true={rec.manageEdit.Name}>
<lightning-input class="clsName" data-colname="Name" data-recid={rec.Id}
data-rowindx={indx} label="Account Name" variant="label-hidden"
value={rec.Name} onchange={handleInputChange} onblur={handleBlur}
onfocusout={handleFocusout}>
</lightning-input>
</template>
<!-- ################################ -->
</td>
<!--#################### Name Td End #################### -->
<!--#################### AccountNumber Td Start #################### -->
<td role="" onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="AccountNumber" data-recid={rec.Id} data-rowindx={indx}
class={rec.manageEdit.c_AccountNumber}>
<!--#################### Viem Mode #################### -->
<template if:false={rec.manageEdit.AccountNumber}>
<span class="slds-grid slds-grid--align-spread forceInlineEditCell"
onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="AccountNumber" data-recid={rec.Id} data-rowindx={indx}>
<span onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="AccountNumber" data-recid={rec.Id} data-rowindx={indx}
class="slds-truncate" title={rec.Name}>{rec.AccountNumber}
</span>
<span class={rec.displayEditIcon.AccountNumber}>
<button data-colname="AccountNumber" onclick={handleEdit}
data-recid={rec.Id} data-rowindx={indx}
class="slds-button slds-button_icon slds-cell-edit__button c__editButtonCss"
tabindex="0">
<lightning-icon data-colname="AccountNumber" data-recid={rec.Id}
data-rowindx={indx} size="xx-small" icon-name="utility:edit"
alternative-text="editIcon">
</lightning-icon>
</button>
</span>
</span>
</template>
<!-- ################################ -->
<!--#################### Edit Mode #################### -->
<template if:true={rec.manageEdit.AccountNumber}>
<lightning-input class="clsAccountNumber" data-colname="AccountNumber"
data-recid={rec.Id} data-rowindx={indx} label="Account Number"
variant="label-hidden" value={rec.AccountNumber}
onchange={handleInputChange} onblur={handleBlur}
onfocusout={handleFocusout}>
</lightning-input>
</template>
<!-- ################################ -->
</td>
<!--#################### AccountNumber Td End #################### -->
<!--#################### Type Td Start #################### -->
<td role="" onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Type" data-recid={rec.Id} data-rowindx={indx}
class={rec.manageEdit.c_Type}>
<!--#################### Viem Mode #################### -->
<template if:false={rec.manageEdit.Type}>
<span class="slds-grid slds-grid--align-spread forceInlineEditCell"
onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Type" data-recid={rec.Id} data-rowindx={indx}>
<span onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Type" data-recid={rec.Id} data-rowindx={indx}
class="slds-truncate" title={rec.Type}>{rec.Type}
</span>
<span class={rec.displayEditIcon.Type}>
<button data-colname="Type" data-recid={rec.Id} data-rowindx={indx}
onclick={handleEdit}
class="slds-button slds-button_icon slds-cell-edit__button c__editButtonCss"
tabindex="0">
<lightning-icon data-colname="Type" data-recid={rec.Id}
data-rowindx={indx} size="xx-small" icon-name="utility:edit"
alternative-text="editIcon">
</lightning-icon>
</button>
</span>
</span>
</template>
<!-- ################################ -->
<!--#################### Edit Mode #################### -->
<template if:true={rec.manageEdit.Type}>
<lightning-record-edit-form record-id={rec.Id} object-api-name="Account"
onsuccess={handleSuccess} onsubmit={handleSubmit}>
<lightning-input-field field-name="Type" class="clsType" tabindex="0"
onblur={handleBlur} onfocusout={handleFocusout} data-rowindx={indx}
data-colname="Type" data-recid={rec.Id} onchange={handleInputChange}>
</lightning-input-field>
</lightning-record-edit-form>
</template>
<!-- ################################ -->
</td>
<!--#################### Type Td End #################### -->
<!--#################### Industry Td Start #################### -->
<td role="" onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Industry" data-recid={rec.Id} data-rowindx={indx}
class={rec.manageEdit.c_Industry}>
<!--#################### Viem Mode #################### -->
<template if:false={rec.manageEdit.Industry}>
<span class="slds-grid slds-grid--align-spread forceInlineEditCell"
onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Industry" data-recid={rec.Id} data-rowindx={indx}>
<span onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Industry" data-recid={rec.Id} data-rowindx={indx}
class="slds-truncate" title={rec.Industry}>{rec.Industry}
</span>
<span class={rec.displayEditIcon.Industry}>
<button data-colname="Industry" data-recid={rec.Id} data-rowindx={indx}
onclick={handleEdit}
class="slds-button slds-button_icon slds-cell-edit__button c__editButtonCss"
tabindex="0">
<lightning-icon data-colname="Industry" data-recid={rec.Id}
data-rowindx={indx} size="xx-small" icon-name="utility:edit"
alternative-text="editIcon">
</lightning-icon>
</button>
</span>
</span>
</template>
<!-- ################################ -->
<!--#################### Edit Mode #################### -->
<template if:true={rec.manageEdit.Industry}>
<lightning-record-edit-form record-id={rec.Id} object-api-name="Account"
onsuccess={handleSuccess} onsubmit={handleSubmit}>
<lightning-input-field field-name="Industry" class="clsIndustry"
tabindex="0" onblur={handleBlur} onfocusout={handleFocusout}
data-rowindx={indx} data-colname="Industry" data-recid={rec.Id}
onchange={handleInputChange}>
</lightning-input-field>
</lightning-record-edit-form>
</template>
<!-- ################################ -->
</td>
<!--#################### Industry Td End #################### -->
<!--#################### Phone Td Start #################### -->
<td role="" onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Phone" data-recid={rec.Id} data-rowindx={indx}
class={rec.manageEdit.c_Phone}>
<!--#################### Viem Mode #################### -->
<template if:false={rec.manageEdit.Phone}>
<span class="slds-grid slds-grid--align-spread forceInlineEditCell"
onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Phone" data-recid={rec.Id} data-rowindx={indx}>
<span onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Phone" data-recid={rec.Id} data-rowindx={indx}
class="slds-truncate" title={rec.Phone}>{rec.Phone}
</span>
<span class={rec.displayEditIcon.Phone}>
<button data-colname="Phone" data-recid={rec.Id} data-rowindx={indx}
onclick={handleEdit}
class="slds-button slds-button_icon slds-cell-edit__button c__editButtonCss"
tabindex="0">
<lightning-icon data-colname="Phone" data-recid={rec.Id}
data-rowindx={indx} size="xx-small" icon-name="utility:edit"
alternative-text="editIcon">
</lightning-icon>
</button>
</span>
</span>
</template>
<!-- ################################ -->
<!--#################### Edit Mode #################### -->
<template if:true={rec.manageEdit.Phone}>
<lightning-input class="clsPhone" data-colname="Phone" data-recid={rec.Id}
data-rowindx={indx} label="Phone" variant="label-hidden" value={rec.Phone}
onchange={handleInputChange} onblur={handleBlur}
onfocusout={handleFocusout}>
</lightning-input>
</template>
<!-- ################################ -->
</td>
<!--#################### Phone Td End #################### -->
<!--#################### Active__c Td Start #################### -->
<td role="" onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Active__c" data-recid={rec.Id} data-rowindx={indx}
class={rec.manageEdit.c_Active__c}>
<!--#################### Viem Mode #################### -->
<template if:false={rec.manageEdit.Active__c}>
<span class="slds-grid slds-grid--align-spread forceInlineEditCell"
onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Active__c" data-recid={rec.Id} data-rowindx={indx}>
<span onmouseover={handleMouseover} onmouseout={handleMouseOut}
data-colname="Active__c" data-recid={rec.Id} data-rowindx={indx}
class="slds-truncate" title={rec.Active__c}>{rec.Active__c}
</span>
<span class={rec.displayEditIcon.Active__c}>
<button data-colname="Active__c" data-recid={rec.Id} data-rowindx={indx}
onclick={handleEdit}
class="slds-button slds-button_icon slds-cell-edit__button c__editButtonCss"
tabindex="0">
<lightning-icon data-colname="Active__c" data-recid={rec.Id}
data-rowindx={indx} size="xx-small" icon-name="utility:edit"
alternative-text="editIcon">
</lightning-icon>
</button>
</span>
</span>
</template>
<!-- ################################ -->
<!--#################### Edit Mode #################### -->
<template if:true={rec.manageEdit.Active__c}>
<lightning-record-edit-form record-id={rec.Id} object-api-name="Account"
onsuccess={handleSuccess} onsubmit={handleSubmit}>
<lightning-input-field field-name="Active__c" class="clsActive__c"
tabindex="0" onblur={handleBlur} onfocusout={handleFocusout}
data-rowindx={indx} data-colname="Active__c" data-recid={rec.Id}
onchange={handleInputChange}>
</lightning-input-field>
</lightning-record-edit-form>
</template>
<!-- ################################ -->
</td>
<!--#################### Active__c Td End #################### -->
</tr>
</template>
</tbody>
<!-- #################### Table Body End #################### -->
</table>
<!-- #################### Custom Table End #################### -->
<!-- #################### Footer Start #################### -->
<div if:true={displayFooter} class="c_footer">
<div class="slds-modal__footer">
<button class="slds-button slds-button_neutral" aria-label="Cancel and close"
onclick={handleCancel}>Cancel
</button>
<button class="slds-button slds-button_brand" onclick={handleSave}>Save
</button>
</div>
</div>
<!-- #################### Footer End #################### -->
</lightning-layout-item>
</lightning-layout>
</lightning-card>
</template>
Step 3 : InlineEditingInLwc.JS
/* Author : Ravi Soni
Date : 25 May 2022
Content: Inline Editing In Lwc
*/
import { LightningElement, wire,track } from 'lwc';
/* Fetching Account Records By Apex */
import fetchAccounts from '@salesforce/apex/InlineEditingInLwcCtrl.fetchAccounts';
/* Updating Account Records By Apex */
import updateAccounts from '@salesforce/apex/InlineEditingInLwcCtrl.updateAccounts';
/* Toast Notification */
import {
ShowToastEvent
} from 'lightning/platformShowToastEvent';
/* Using Refresh Apex For Getting Updated Records */
import {
refreshApex
} from '@salesforce/apex';
/* ############## Private Property Start ############ */
let hasValueChange = false;
let oldData = [];
let lstDraftValues = [];
let exisitingData = [];
/* Using this property for display View Mode */
let obj = {
"Name": false,
"AccountNumber": false,
"Type": false,
"Industry": false,
"Active__c": false,
"Phone": false,
"c_Name": "",
"c_AccountNumber": "",
"c_Type": "",
"c_Industry": "",
"c_Active__c": "",
"c_Phone": ""
};
/* ############################################### */
/* Using this property for hide pencil Icon */
let displayEditButtonObj = {
"Name": 'c__iconHidden',
"AccountNumber": 'c__iconHidden',
"Type": 'c__iconHidden',
"Industry": 'c__iconHidden',
"Active__c": 'c__iconHidden',
"FTS_Term_End__c": 'c__iconHidden',
"Phone": 'c__iconHidden'
};
/* ############################################### */
/* ############ Private Property End ############ */
export default class InlineEditingInLwc extends LightningElement {
/* ############## Public Property Starts ############ */
displayFooter = false;
isLoading = true;
allResponse = [];
lstRecords = [];
/* ############## Public Property Ends ############ */
/* ############## Fetching account Records ############ */
(fetchAccounts) getRecords(response) {
this.allResponse = response; //Store all the response for refresh data
let {
data,
error
} = response;
if (data) {
hasValueChange = false;
lstDraftValues = [];
this.displayFooter = false;
let result = JSON.parse(JSON.stringify(data));
exisitingData = JSON.parse(JSON.stringify(data));
for (let i = 0; i < result.length; i++) {
result[i].displayEditIcon = displayEditButtonObj;
result[i].manageEdit = obj;
}
this.isLoading = false;
oldData = JSON.parse(JSON.stringify(result));
this.lstRecords = result;
} else if (error) {
console.log('@InlineEditingInLwc error=====> ' + JSON.stringify(error));
}
}
/* ############## ######################## ############ */
/* ############## Handle Input Change Event ############ */
handleInputChange(event) {
this.helperMethod(event, 'handleInputChange');
}
/* ############### It is the helper method of every event ############### */
helperMethod(event, eventName) {
let colname = event.target.dataset.colname;
let rowNo = Number(event.target.dataset.rowindx);
let currentRow = JSON.parse(JSON.stringify(this.lstRecords[rowNo]));
let currentValue = event.target.value;
let self = this;
let sTime = 500;
if (eventName == 'handleMouseover') {
currentRow.displayEditIcon[colname] = '';
} else if (eventName == 'handleInputChange') {
let oldValue = currentRow[colname];
/* if value get change, changing the td background color */
if (oldValue != currentValue) {
currentRow.manageEdit['c_' + colname] = 'c__tdBackgroundColor';
hasValueChange = true;
}
currentRow[colname] = currentValue;
}
/* displaying the pencil icon */
else if (eventName == 'handleMouseOut') {
currentRow.displayEditIcon[colname] = 'c__iconHidden';
} else if (eventName == 'handleBlur') {
currentRow.manageEdit[colname] = false;
this.displayFooter = hasValueChange;
} else if (eventName == 'handleFocusout') {
sTime = 100;
setTimeout(function() {
currentRow.manageEdit[colname] = false;
self.lstRecords[rowNo] = JSON.parse(JSON.stringify(currentRow));
self.displayFooter = hasValueChange;
}, sTime);
}
/* if event is handleEdit, do focus on input field */
else if (eventName == 'handleEdit') {
currentRow.manageEdit[colname] = true;
if (colname == "Industry" || colname == "Type" || colname == "Active__c") {
sTime = 1500;
}
setTimeout(function() {
self.template.querySelector('.cls' + colname).focus();
}, sTime);
}
this.lstRecords[rowNo] = JSON.parse(JSON.stringify(currentRow));
}
/* ################# It is the focusout and blur helperMethod ################# */
helperFocusOut(event) {
let recId = event.target.dataset.recid;
let colname = event.target.dataset.colname;
let rowNo = Number(event.target.dataset.rowindx);
let currentValue = event.target.value;
let oldRecord = JSON.parse(JSON.stringify(oldData[rowNo]));
let exisitingRecord = JSON.parse(JSON.stringify(exisitingData[rowNo]));
if (oldRecord[colname] != currentValue) {
if (exisitingRecord.Id == recId) {
exisitingRecord[colname] = currentValue;
}
if (lstDraftValues.length == 0) {
lstDraftValues.push(exisitingRecord);
} else {
let hasRecMatch = false;
for (let i = 0; i < lstDraftValues.length; i++) {
if (lstDraftValues[i].Id == recId) {
lstDraftValues[i][colname] = currentValue;
hasRecMatch = true;
break;
}
}
if (!hasRecMatch) {
lstDraftValues.push(exisitingRecord);
}
}
}
}
/* ################################## */
/* ############ When User MouseOver On Td, Pencil Icon Will Display ############ */
handleMouseover(event) {
this.helperMethod(event, 'handleMouseover');
}
/* ############################### */
/* ############ When User MouseOut From Td, Pencil Icon Will Hide ############ */
handleMouseOut(event) {
this.helperMethod(event, 'handleMouseOut');
}
/* ############################### */
/* ############ When User Click On Pencil Icon, It will Display Input Box And Will Do Focus On Input ############### */
handleEdit(event) {
this.helperMethod(event, 'handleEdit');
}
/* ############################### */
/* ############ When User Click Out From Input ,It will Hide Input And Display View Mode ############### */
handleBlur(event) {
this.helperMethod(event, 'handleBlur');
this.helperFocusOut(event);
}
/* ############################### */
/* ############ When User Click Out From Picklist ,It will Hide Picklist And Display View Mode ############### */
handleFocusout(event) {
this.helperMethod(event, 'handleFocusout');
this.helperFocusOut(event);
}
/* ############################### */
/* ################ It Will Cancle All The Changes ################# */
handleCancel() {
this.lstRecords = JSON.parse(JSON.stringify(oldData));
lstDraftValues = [];
this.displayFooter = false;
hasValueChange = false;
}
/* ############################### */
/* ################ It Will Save Only Draft Values ################# */
handleSave() {
this.isLoading = true;
let sMessage = '';
updateAccounts({
updateRecords: lstDraftValues
}).then(() => {
sMessage = 'Record(s) have been updated successfuly';
this.showToastNotification('Success!', sMessage, 'success');
refreshApex(this.allResponse); //getting newly updated data
}).catch(error => {
this.isLoading = false;
console.log('@Sfdcfamily error =======> ' + JSON.stringify(error));
sMessage = error.body.message;
this.showToastNotification('Error!', sMessage, 'error');
});
}
/* ############################################ */
/* Fire Toast Notification */
showToastNotification(sTitle, sMessage, sVariant) {
this.dispatchEvent(
new ShowToastEvent({
title: sTitle,
message: sMessage,
variant: sVariant
})
);
}
/* ################################# */
}
Step 4 : InlineEditingInLwc.CSS
.c__tdBackgroundColor {
background: rgb(250, 255, 189);
}
.c_footer {
position: sticky ;
bottom: 0 ;
}
.slds-modal__footer {
text-align: center ;
}
.c__iconHidden {
visibility: hidden;
}
.c__editButtonCss {
float: right;
opacity: 0.6;
}
Step 5 : InlineEditingInLwc.js-meta.xml
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
Output :
If You have any doubt or suggestion related this post , please comment us and share your opinion with us. We respect your opinion.
I hope you liked it.
Happy Learning
0 Comments
If you have any doubts please comment us