Hello friends, today we are going to discuss Efficient Server-Side Pagination in LWC: No Offset Approach. Pagination is a common requirement when dealing with large data sets in Salesforce applications. In this blog post, we’ll explore an efficient server-side pagination approach using Lightning Web Components (LWC) without relying on offsets. By avoiding offsets, we can improve performance and simplify our code.
Also, check this: Datatable using GraphQL in LWC
Key Highlights :
- Performance: No-offset pagination performs well even with large data sets
- Simplicity: No need to calculate offsets or handle edge cases.
- Consistency: Records remain consistent during pagination.
- Reduced Complexity: Eliminating offsets simplifies the code, making it easier to maintain and understand.
Code :
EfficientPaginationController.cls:
/**
* @description : This class used for. LWC
* @coverage : UnlimitedPaginationControllerTest.cls | @CC100%
* @author : zuberrangreaz8@gmail.com
* @group : Techdicer
* @last modified on : 19-02-2024
* @last modified by : zuberrangreaz8@gmail.com
* Modifications Log
* Ver Date Author Modification
* 1.0 19-02-2024 zuberrangreaz8@gmail.com Initial Version | Story Number | @CC100%
**/
public with sharing class EfficientPaginationController {
/**
* Fetches a list of accounts based on pagination parameters.
*
* @param buttonTypePrevious Boolean indicating if it's a request for previous records.
* @param buttonTypeNext Boolean indicating if it's a request for next records.
* @param firstId Id of the first record in the current page.
* @param lastId Id of the last record in the current page.
* @param recordsLimit Number of records to retrieve in a single request.
* @return List of Account records based on the pagination criteria.
*/
@AuraEnabled
public static List<Account> fetchAccount(Boolean buttonTypePrevious, Boolean buttonTypeNext, String firstId, String lastId, Integer recordsLimit) {
List<Account> accountList = new List<Account>();
if (buttonTypeNext == true) {
// Fetch records with Id greater than the lastId
accountList = [SELECT Id, Name, Phone, Fax, Site FROM Account WHERE Id > :lastId ORDER BY Id ASC LIMIT :recordsLimit];
} else if (buttonTypePrevious == true) {
// Fetch records with Id less than the firstId
accountList = [SELECT Id, Name, Phone, Fax, Site FROM Account WHERE Id < :firstId ORDER BY Id DESC LIMIT :recordsLimit];
} else {
// Fetch the first page of records
accountList = [SELECT Id, Name, Phone, Fax, Site FROM Account ORDER BY Id ASC LIMIT :recordsLimit];
}
if (!accountList.isEmpty()) {
return accountList;
}
return null;
}
/**
* Retrieves the total count of Account records.
*
* @return Integer representing the total count of Account records.
*/
@AuraEnabled(cacheable = true)
public static Integer recordCount() {
Integer countResult = [SELECT COUNT() FROM Account];
System.debug('countResult => ' + countResult);
return countResult;
}
}
pagination.html :
<!--
@description :
@author : zuberrangreaz8@gmail.com
@group : Techdicer
@last modified on : 19-02-2024
@last modified by : zuberrangreaz8@gmail.com
Modifications Log
Ver Date Author Modification
1.0 19-02-2024 zuberrangreaz8@gmail.com Initial Version | Story Number
-->
<template>
<lightning-card title="Pagination with Unlimited Data Account Records" icon-name="standard:account">
<template if:true={showLoading}>
<lightning-spinner alternative-text="Loading" size="medium" class="spinnerClass">
</lightning-spinner>
</template>
<div class="slds-m-around_medium">
<lightning-datatable key-field="id" hide-checkbox-column="true" show-row-number-column="true"
data={accounts} columns={columns}>
</lightning-datatable>
</div>
<lightning-layout class="slds-p-around_small">
<div class="slds-align_absolute-center">
<lightning-layout-item>
<lightning-button label="Previous" icon-name="utility:chevronleft" data-type="previous"
onclick={previousHandler} disabled={disablePrevious}>
</lightning-button>
</lightning-layout-item>
<lightning-layout-item flexibility="grow" class="slds-p-left_medium"></lightning-layout-item>
<lightning-layout-item>
<lightning-button label="Next" icon-name="utility:chevronright" data-type="next"
icon-position="right" onclick={nextHandler} disabled={disableNext}></lightning-button>
</lightning-layout-item>
</div>
</lightning-layout>
</lightning-card>
</template>
pagination.js :
/**
* @description :
* @author : techdicerkeeplearning@gmail.com
* @group :
* @last modified on : 19-02-2024
* @last modified by : techdicerkeeplearning@gmail.com
* Modifications Log
* Ver Date Author Modification
* 1.0 19-02-2024 zuberrangreaz8@gmail.com Initial Version
**/
import { LightningElement, api, track, wire } from 'lwc';
import fetchAccount from "@salesforce/apex/EfficientPaginationController.fetchAccount";
import recordCount from "@salesforce/apex/EfficientPaginationController.recordCount";
// Define columns for the data table
const columns = [
{ label: 'Name', fieldName: 'Name' },
{ label: 'Phone', fieldName: 'Phone' },
{ label: 'Fax', fieldName: 'Fax' },
];
export default class UnlimitedPagination extends LightningElement {
// Public properties
@api recordsPerPage = 10;
// Data table columns
columns = columns;
// State variables
@track accounts = [];
@track showLoading = false;
searchKey;
@api lastId;
@api firstId;
@api buttonTypePrevious;
@api buttonTypeNext;
totalRecountCount = 0;
totalPage = 0;
pageNumber = 1;
// Initialization when the component is connected
connectedCallback() {
this.getRecords();
}
// Wire service to retrieve the total record count
@wire(recordCount)
wiredAccounts({ error, data }) {
if (data) {
// Update total record count and calculate total pages
this.totalRecountCount = data;
this.totalPage = Math.ceil(this.totalRecountCount / this.recordsPerPage);
// Ensure pageNumber is within valid range
if (this.pageNumber <= 1) {
this.pageNumber = 1;
} else if (this.pageNumber >= this.totalPage) {
this.pageNumber = this.totalPage;
}
} else if (error) {
this.error = error;
this.data = undefined;
}
}
// Disable the "Previous" button when on the first page
get disablePrevious() {
return this.pageNumber == 1;
}
// Disable the "Next" button when on the last page
get disableNext() {
return this.pageNumber == this.totalPage;
}
// Fetch records based on pagination parameters
getRecords() {
this.showLoading = true;
fetchAccount({
buttonTypePrevious: this.buttonTypePrevious,
buttonTypeNext: this.buttonTypeNext,
firstId: this.firstId,
lastId: this.lastId,
recordsLimit: this.recordsPerPage
})
.then(result => {
// Update accounts data and pagination details
this.accounts = result;
this.firstId = result[0].Id;
this.lastId = result[result.length - 1].Id;
// Sort accounts if navigating to the previous page
if (this.buttonTypePrevious === true) {
this.accounts.sort((a, b) => (a.Id > b.Id) ? 1 : -1);
}
this.showLoading = false;
})
.catch(error => {
this.showLoading = false;
console.error('Error: ' + error.body.message);
});
}
// Handle click on "Previous" button
previousHandler() {
if (this.pageNumber > 1) {
this.pageNumber = this.pageNumber - 1;
this.buttonTypePrevious = true;
this.buttonTypeNext = false;
this.getRecords();
}
}
// Handle click on "Next" button
nextHandler() {
if ((this.pageNumber < this.totalPage) && this.pageNumber !== this.totalPage) {
this.pageNumber = this.pageNumber + 1;
this.buttonTypeNext = true;
this.buttonTypePrevious = false;
this.getRecords();
}
}
// Handle search key input change
handelSearchKey(event) {
this.searchKey = event.target.value;
}
// Show all records by resetting pagination
showAllRecords() {
this.getRecords();
}
}
pagination.js-meta.xml :
<?xml version="1.0"?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>57.0</apiVersion> <isExposed>true</isExposed> <targets> <target>lightning__HomePage</target> <target>lightning__Tab</target> </targets> </LightningComponentBundle>
Output :
Reference :
What’s your Reaction?
+1
4
+1
+1
+1
+1
3
+1

3 comments
Can we have a sort function implemented on this pagination
Is there any possibility to perform sort using this functionality
Yes we can