Lightning Web Components
Easiest way to implement pagination in Lightning Web Component
Pagination in Lightning Datatable is a common requirement in Salesforce development. While the concept is straightforward, new developers often find it challenging to implement effectively. In this blog post, we’ve broken down the process into simple.Lets discuss some Key features and Technical Insights first.
Key Features
- ✓Pagination in LWC with Previous and Next buttons.
- ✓Displaying the current page and total number of pages.
- ✓Showing the total number of records.
- ✓Using the standard Lightning Datatable.
Technical Insights
- ✓How to resolve "Apex heap size too large" ?
- ✓Using @wire decorator Client-Side Caching.
- ✓Returning a map of records from Apex and using it in LWC.
- ✓Understanding how to use LIMIT and OFFSET in SOQL effectively.
Code Files
Exactly as used in the demo above.
HTML
<template>
<div>
<div class="slds-card slds-p-around_large" >
<div class="slds-text-align_right">
<div class="slds-p-bottom_large">
<lightning-button label="Previous" onclick={handlePrevious} disabled={disablePreviousButton}></lightning-button>
<lightning-button class="slds-m-left_large" label="Next" variant="brand" onclick={handleNext} disabled={deleteButtonReadOnly}></lightning-button>
</div>
</div>
<div class="slds-text-align_right">
<span class="slds-text-body_regular">
Displaying {currentPage} of {totalPages} Page
</span>
</div>
<div>
<lightning-datatable
data={lstRecords}
columns={columns}
key-field="Id"
show-checkbox-column="true"
sorted-direction={sortDirection}
sorted-by={sortedBy}
onsort={handleSortAccountData}
></lightning-datatable>
</div>
<div class="slds-text-align_right slds-p-top_small">
Total records: <b>{totalRecords}</b>
</div>
</div>
</div>
</template> Java Script
import { LightningElement, wire,track } from 'lwc';
import getRecords from '@salesforce/apex/PaginationDemoController.getRecords';
import { refreshApex } from '@salesforce/apex';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { NavigationMixin } from 'lightning/navigation';
export default class DatatablePagination extends NavigationMixin(LightningElement) {
objectName = 'Account';
lstRecords;
disablePreviousButton = true;
offset = 0;
totalRecords = 0;
currentPage = 1;
totalPages = 1;
recordPerPages = 5;
columns = [
{ label: 'Id', fieldName: 'Id', type: 'text' },
{ label: 'Name', fieldName: 'Name', type: 'text',sortable: true },
{ label: 'Account Number', fieldName: 'AccountNumber', type: 'picklist' },
{ label: 'Rating', fieldName: 'Rating', type: 'text' },
{ label: 'Created Date', fieldName: 'CreatedDate', type: 'date' , typeAttributes:{day:'numeric',month:'short',year:'numeric', hour:'2-digit',minute:'2-digit',hour12:true}},
];
headers ={
Id:"Id",
Name:"Name",
AccountNumber:"Account Number",
Rating:"Rating",
CreatedDate:"Created Date",
}
@wire(getRecords, { objectName: '$objectName', queryLimit: 5, offset: '$offset' })
getRecords(result) {
this.wiredRecords = result;
if (result.data) {
if(result.data.records && result.data.records.length){
this.totalRecords = result.data.totalRecords;
this.lstRecords = result.data.records;
this.totalPages = Math.ceil(this.totalRecords / this.recordPerPages);
} else{
console.error('Error fetching records', result);
}
} else if (result.error) {
console.error('Error fetching records', result.error);
}
}
handleNext() {
this.disablePreviousButton = false;
this.offset = this.offset + 5;
this.currentPage += 1;
}
handlePrevious() {
this.offset = this.offset - 5;
this.currentPage -= 1;
if(this.offset == 0) {
this.disablePreviousButton = true;
this.offset =0;
}
}
refreshData() {
refreshApex(this.wiredRecords);
}
showtoast(message, variant) {
this.dispatchEvent(
new ShowToastEvent({
title: message,
variant: variant
})
);
}
handleSortAccountData(event) {
this.sortBy = event.detail.fieldName;
this.sortDirection = event.detail.sortDirection;
this.sortAccountData(event.detail.fieldName, event.detail.sortDirection);
}
sortAccountData(fieldname, sortDirection) {
let parseData = JSON.parse(JSON.stringify(this.lstRecords));
let keyValue = (a) => {
return a[fieldname];
};
let isReverse = sortDirection === 'asc' ? 1: -1;
parseData.sort((x, y) => {
x = keyValue(x) ? keyValue(x) : '';
y = keyValue(y) ? keyValue(y) : '';
if(x > y){
return sortDirection === 'asc' ? -1 : 1;}
else if(y > x){
return sortDirection === 'asc' ? 1 : -1;}
else return 0;
});
this.lstRecords = parseData;
}
} Apex Controller
public with sharing class PaginationDemoController {
@AuraEnabled(cacheable=true)
public static Map<String, Object> getRecords(String objectName, Integer queryLimit, Integer offset) {
String query = 'SELECT Id, Name, AccountNumber, Rating, CreatedDate FROM ' + objectName + ' LIMIT ' + queryLimit + ' OFFSET ' + offset;
String queryWitoutLimit = 'SELECT Id, Name, AccountNumber, Rating, CreatedDate FROM ' + objectName;
List<sObject> lst = Database.query(queryWitoutLimit);
Integer size = lst.size();
return new Map<String, Object>{
'records' => Database.query(query),
'totalRecords' => size
};
}
} Building something similar?
Explore more reusable LWC patterns or Apex fundamentals to go with it.