Client Side Pagination in LWC Component

 Hi Folks, Hope you all are well !!

In this post, we are gonna implement a simple client side pagination. Making use of client side pagination is much more simple then having all logic into Apex Class and doing SOQL on each click of Pre and Next button.

Let's simplify pagination in below steps :-

  • Get all the result in single Apex call.
  • Hold the main result to a object type variable which further will be used to process the logic on each pre/next button click.
  • Decide how many records needed to show on the page.
  • Process the logic for displaying default number of records and when click on pre and next button.
  • Handle the logic when records on page got changed.
  • for the pagination logic, we have created a separate (child component) which will takes some property from its parent component and will process it accordingly. (Reusability feature).

paginationlwc.cmp

<template>
    <lightning-card title={cardTitle}>
        <div style="height: 200px;">
            <lightning-datatable key-field="Id"
                                data={filterdContacts}
                                columns={column}>
            </lightning-datatable>
        </div>
        <div slot="footer" >
            <c-lwc-pagination
                object-data-list={contacts}
                total-pages={totalPages}
                onpagination={handleDataAfterPagination}>
            </c-lwc-pagination>
           
        </div>
    </lightning-card>
   
</template>


paginationlwc.js

import { LightningElement, wire,track } from 'lwc';

import getContacts from '@salesforce/apex/ContactController.getContacts';

const column = [
    {label:'First Name', fieldName : 'FirstName', type:'text'},
    {label:'Last Name', fieldName : 'LastName', type:'text'},
    {label:'Email', fieldName:'Email', type:'email'},
    {label:'Phone', fieldName:'Phone', type:'phone'}
];

export default class Paginationlwc extends LightningElement {

    column = column;

    contacts = [];
    @track filterdContacts;
    cardTitle = 'Contacts';
    recordsPerPage = 5;
    totalPages;
    totalRecords;

    @wire(getContacts)
    wiredContacts({error, data}){
        if(data){
            let contactsArray = [];
            for(let i=0; i<this.recordsPerPage; i++){
                if(data.length > i){
                    contactsArray.push(data[i]);
                }
            }
            this.filterdContacts = [...contactsArray];
            this.contacts = data;
            this.totalRecords = data.length;
            this.totalPages = Math.ceil(this.totalRecords / this.recordsPerPage);
            this.cardTitle =  this.totalRecords ? `Contacts (${this.totalRecords})` : 'Contacts';
        }
        else if(error){
            this.dispatchEvent(
                new CustomEvent({title : 'Error Loading contacts', message:error.message, variant :'error'})
            );
        }
    }

    handleDataAfterPagination(event) {
        this.filterdContacts = event.detail;
    }

}


lwcPagination.html (Child Component)

<template>
    <lightning-layout>
        <lightning-layout-item size="2"></lightning-layout-item>
        <lightning-layout-item size="4">
            <lightning-combobox label="Records per Page" variant="label-stacked" dropdown-alignment="bottom-left"
                                options={recordsPerPageOptions}
                                name="recordonPageCombobox"
                                onchange={handleRecordonPageChange}
                                value={recordsPerPageStr}>
            </lightning-combobox>
        </lightning-layout-item>
        <lightning-layout-item size="4" padding="around-small" style="display: flex;">
            <div class="slds-p-around_x-small">
                <lightning-button-icon variant="bare" size="large" icon-name="utility:jump_to_left" title="First" onclick={handleFirstClick}
                                        disabled={isFirstButtonDisabled}></lightning-button-icon>
            </div>
            <div class="slds-p-around_x-small">
                <lightning-button-icon variant="bare" size="large" icon-name="utility:left" title="Pre" onclick={handlePreviousClick}
                                        disabled={isPreButtonDisabled}></lightning-button-icon>
            </div>
            <div class="slds-p-around_x-small">
            <span class="slds-text-heading_medium">Page {currentPage} of {totalPages}</span>
            </div>
            <div class="slds-p-around_x-small">
                <lightning-button-icon variant="bare" size="large" icon-name="utility:right" title="Next" onclick={handleNextClick}
                                        disabled={isNextButtonDisabled}></lightning-button-icon>
            </div>
            <div class="slds-p-around_x-small">
                <lightning-button-icon variant="bare" size="large" icon-name="utility:jump_to_right" title="First" onclick={handleLastClick}
                                        disabled={isLastButtonDisabled}></lightning-button-icon>
            </div>
        </lightning-layout-item>
        <lightning-layout-item size="2"></lightning-layout-item>
    </lightning-layout>
</template>

lwcPagination.js (Child Component)

import { LightningElement, api, track } from 'lwc';

const RECORDS_PER_PAGE_OPTIONS = [
    {label : '5', value : '5'},
    {label : '10', value : '10'},
    {label : '15', value : '15'},
    {label : '20', value : '20'}
];

export default class LwcPagination extends LightningElement {

    recordsPerPageOptions = RECORDS_PER_PAGE_OPTIONS;
    @track filterdObjDataList;

    @api objectDataList;
    @api totalPages;
    recordsPerPageStr;
    recordsPerPage = 5;
    currentPage = 1;

    connectedCallback() {
        this.recordsPerPageStr = this.recordsPerPage.toString();
        console.log('totalPages ::', this.totalPages);
    }

    handleFirstClick() {
        this.currentPage = 1;
        this.doThePaginationLogic();
    }
    handleLastClick() {
        this.currentPage = this.totalPages;
        this.doThePaginationLogic();
    }
    handleNextClick() {
        this.currentPage += 1;
        this.doThePaginationLogic();
    }
    handlePreviousClick(){
        this.currentPage -= 1;
        this.doThePaginationLogic();
    }

    handleRecordonPageChange(event){
        let recordsValue = event.detail.value;
        this.recordsPerPageStr = recordsValue;
        this.recordsPerPage = parseInt(recordsValue);
        this.start = 0;
        this.currentPage = 1;
        this.totalPages = Math.ceil(this.objectDataList.length / this.recordsPerPage);

        this.doThePaginationLogic();
    }

    doThePaginationLogic() {
        let dataList = this.objectDataList;
        let filterdList = [];
        let startSlice = (this.currentPage -1) * this.recordsPerPage;
        let endSlice = startSlice + parseInt(this.recordsPerPage);
        filterdList = dataList.slice(startSlice, endSlice);

        this.filterdObjDataList = [...filterdList];
       
        //dispatch the event to send filtered data to parent cmp.
        const paginationEvent = new CustomEvent('pagination', {detail : this.filterdObjDataList});
        this.dispatchEvent(paginationEvent);
    }

    get isPreButtonDisabled() {
        return this.currentPage <= 1 ? true : false;
    }
    get isNextButtonDisabled() {
        return this.currentPage === this.totalPages ? true : false;
    }
    get isFirstButtonDisabled() {
        return this.currentPage <= 1 ? true : false;
    }
    get isLastButtonDisabled() {
        return this.currentPage === this.totalPages ? true : false;
    }

}


Result





Comments

Popular posts from this blog

How to show or hide a particular section of Visualforce Page dependent upon picklistfield value

Process Automation Specialist Superbadge

Dynamically Add/Delete rows in Visualforce Page