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
Just copy and paste the following code, and your pagination will be ready to go:
Note: Replace the apex imports according to your class names.
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
};
}
}