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
3
+1
+1
+1
+1
2
+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