June 17, 2023
This blog will be helpful for you. This blog is on a custom table with pagination and you can select multiple records, checkbox will not remove after even changing the pages of the table when you go back to the previous page checked records will exist. Also, you can inline edit records in a custom table.
Let's go ahead and start with How we can begin to do this work. We will make component (name- customTable) for the custom table in LWC. Create a CSS file with the same name as the component. To show records in a custom table we also make a wrapper class in the apex (name-CustomeTableController).
Here is brief info of Wrapper class, a wrapper class is a custom Apex class that encapsulates or wraps related data fields from different objects or types into a single object. It allows developers to organize and manage data more efficiently by creating a single container that holds multiple related data elements.
Class Code
CustomeTableController.apxc
public with sharing class CustomeTableController {public CustomeTableController() {
}
@AuraEnabled(cacheable=true)public static String retrieveContact(){
List<contactWrap> contWrapList = new List<contactWrap>();try {List<Contact> contList = [SELECT Id, Account.Name, Name, Amount__c, Owner.Name FROM Contact where AccountId != null WITH SECURITY_ENFORCED ];for(Contact c : contList){contWrapList.add(new contactWrap(c.Id, c.Account.Name, c.Name, c.Amount__c, c.Owner.Name));}return JSON.serialize(contWrapList);} catch (Exception e) {throw new AuraHandledException(e.getMessage());}}
@AuraEnabledpublic static void updateAmount(Object data) {System.Debug(' data ' + data);List<Contact> accs = new List<Contact>();List<WrapperRequest> updateForAmount = (List<WrapperRequest>) JSON.deserialize(JSON.serialize(data),List<WrapperRequest>.class);for(WrapperRequest wr : updateForAmount){accs.add(new Contact(Id = wr.Id, Amount__c = wr.amount));}System.Debug(' updateForAmount ' + updateForAmount);if(accs.size() == 0)throw new AuraHandledException('Please select the correct record to update');try {update accs;}catch (Exception e) {throw new AuraHandledException(e.getMessage());}}
public class WrapperRequest{Decimal amount;String id;}
public class contactWrap{public String Id;public String AccountName;public String Name;public Decimal Amount;public String OwnerName;public Boolean isSelected;
public contactWrap(String Id, String AccountName, String Name, Decimal Amount, String OwnerName){this.Id = Id;this.AccountName = AccountName;this.Name = Name;this.Amount = Amount;this.OwnerName = OwnerName;this.isSelected = false;}}}
LWC code
customTable.css
/* Chrome, Safari, Edge, Opera */input::-webkit-outer-spin-button,input::-webkit-inner-spin-button {-webkit-appearance: none;margin: 0;}
input[type=number]{border: none;background-color: transparent;}
input[type=number]:focus {outline: none;}
button {background-color: transparent;visibility: hidden;}table tbody tr:hover button {visibility: visible;}
.icon:hover {--slds-c-icon-color-foreground: rgb(255, 255, 255);}
table {border-collapse: collapse;}
table thead tr th {background-color: aliceblue;}
th, td {padding:5px;border-bottom: 1px solid #ddd;}
table tbody tr:hover{background-color: aliceblue;}
customTable.html
<template>
<lightning-quick-action-panel header="Custom Table">
<div class="slds-p-around_none">
<table><thead><tr ><th> </th><th>Account Name</th><th>Contact Name</th><th>Amount__c</th><th>Owner Name</th></tr></thead><tbody><template for:each={data} for:item="list">
<tr class="slds-hint-parent" key={list.Id} ><td><input type="checkbox" checked={list.isSelected} data-check-id={list.Id} onchange={handleCheck} /></td>
<td data-label="Account Name">{list.AccountName}</td>
<td data-label="Contact Name"><a onclick={navigateToContact} target="_blank" data-contact-id={list.Id}>{list.Name}</a></td>
<td data-label="Amount" style="width:2em;" data-selected-td={list.Id}><div class="slds-truncate " title={list.Amount}>
<div class="slds-form-element slds-form-element_edit slds-hint-parent"><div class="slds-form-element__control "><input type="number" disabled value={list.Amount} onchange={handleOnChange} id={indexVar} data-selected-input={list.Id}/><button class="slds-button slds-button_icon" title="Edit: Amount" onclick={handleEdit} name="editBtn" data-edit-id={list.Id}><lightning-icon icon-name='utility:edit' class="icon" alternative-text='edit' size='xx-small' title='edit' data-edit-id={list.Id}></lightning-icon></button></div></div>
</div></td>
<td data-label="Contact Name"><div class="slds-truncate" title={list.OwnerName}>{list.OwnerName}</div></td></tr>
</template></tbody></table></div>
<div slot="footer" ><!-- Pagination Start --><div class="slds-align_absolute-center"><lightning-button disabled={bDisableFirst} icon-name="utility:jump_to_left" label="First"class="slds-p-horizontal_x-small" alternative-text="first page" onclick={firstPage}></lightning-button><lightning-button disabled={bDisableFirst} icon-name="utility:chevronleft" label="Previous"alternative-text="Previous" onclick={previousHandler}></lightning-button> <span class="slds-badge slds-badge_lightest" style="margin-right: 10px;margin-left: 10px;">Page {page} of {totalPage} | Total: {totalRecountCount}</span> <lightning-button disabled={bDisableLast} icon-name="utility:chevronright" label="Next" alternative-text="Next"onclick={nextHandler} class="slds-p-horizontal_x-small" icon-position="right"></lightning-button><lightning-button disabled={bDisableLast} icon-name="utility:jump_to_right" label="Last"alternative-text="last page" onclick={lastPage} icon-position="right"></lightning-button><div style="margin-left: 5em;"><lightning-button variant="neutral" label="Cancel" onclick={handleCancel}></lightning-button><lightning-button variant="brand" label="Save" class="slds-m-left_x-small"onclick={handleSave}></lightning-button></div></div><!-- Pagination End --></div>
</lightning-quick-action-panel>
</template>
customTable.js
import { LightningElement, track} from 'lwc';import { CloseActionScreenEvent } from 'lightning/actions';import { ShowToastEvent } from 'lightning/platformShowToastEvent';import retrieveContact from '@salesforce/apex/CustomeTableController.retrieveContact'import updateAmount from '@salesforce/apex/CustomeTableController.updateAmount'
export default class CustomeTable extends LightningElement {
page = 1;items = [];data = [];
startingRecord = 1;endingRecord = 0;pageSize = 5;totalRecountCount = 0;totalPage = 0;
get bDisableFirst() {return this.page == 1;}get bDisableLast() {return this.page == this.totalPage;}
connectedCallback(){
retrieveContact().then(results=>{this.items = JSON.parse(results);this.totalRecountCount = results.length;this.totalPage = Math.ceil(this.totalRecountCount / this.pageSize);this.data = this.items.slice(0, this.pageSize);this.endingRecord = this.pageSize;this.error = undefined;}).catch(error=>{this.error = error;this.data = undefined;console.log('Result error:', error)})}
recordPerPage(page) {this.startingRecord = ((page - 1) * this.pageSize);this.endingRecord = (this.pageSize * page);this.endingRecord = (this.endingRecord > this.totalRecountCount) ? this.totalRecountCount : this.endingRecord;this.data = this.items.slice(this.startingRecord, this.endingRecord);this.startingRecord = this.startingRecord + 1;}
firstPage() {this.page = 1;this.recordPerPage(this.page)}
previousHandler() {if (this.page > 1) {this.page = this.page - 1;this.recordPerPage(this.page);}}
nextHandler() {if ((this.page < this.totalPage) && this.page !== this.totalPage) {this.page = this.page + 1;this.recordPerPage(this.page);}}
lastPage() {this.page = this.totalPage;this.recordPerPage(this.page)}
handleOnChange(event){const inputId = event.target.dataset.selectedInputconst amount = event.target.value
this.items.forEach(e => {{if(e.Id === inputId){e.Amount = amount;}}});const input = this.template.querySelector(`[data-selected-input="${inputId}"]`)input.setAttribute('disabled')}
handleEdit(event){const editId = event.target.dataset.editId;const td = this.template.querySelector(`[data-selected-td="${editId}"]`)td.style.backgroundColor = 'LemonChiffon'const input = this.template.querySelector(`[data-selected-input="${editId}"]`)input.removeAttribute('disabled')input.focus()}
handleCheck(event){const id = event.target.dataset.checkIdconst checked = event.target.checkedthis.items.forEach(e => {{if(e.Id===id){e.isSelected = checked ;}}});
}
async handleSave(){
let toBeupdated=[];
this.items.forEach(e => {{if(e.isSelected===true){toBeupdated.push(e);}}});
if(toBeupdated.length > 0 ) {try{//Pass edit field to CustomeTableController controllerconsole.log('toBeupdated:', JSON.stringify(toBeupdated))const result = await updateAmount({data:toBeupdated})console.log(JSON.stringify('Apex result:', result))
this.dispatchEvent(new ShowToastEvent({title: 'Success',message: 'Record updated successfully',variant: 'success'}))} catch(error) {this.dispatchEvent(new ShowToastEvent({title: 'Error updating',message: error.body.message,variant: 'error'}))}} else {this.dispatchEvent(new ShowToastEvent({title: 'Error',message: 'No record selected !',variant: 'error'}))}this.handleCancel();}
navigateToContact(e){const contId = e.target.dataset.contactId;this.template.querySelector(`[data-contact-id="${contId}"]`).href=`/lightning/r/${contId}/view`;}handleCancel() {this.dispatchEvent(new CloseActionScreenEvent());}}
customTable.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?><LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"><apiVersion>57.0</apiVersion><isExposed>true</isExposed><targets><target>lightning__RecordAction</target></targets></LightningComponentBundle>
I hope this blog helped you!