Hello friends, In this post, I will share code that helps you to apply pagination on lightning datatable. It's a client side pagination, so no need to do anything on apex side. This example is pretty simple to understandable and applicable in lightning component. So let's get started,

Pagination with search in lightning datatable

In the below code, I have used account data, you can replace it with any sobject.

PaginationHandler.apxc

 public with sharing class PaginationHandler {

@AuraEnabled
public static Map<String, Object> getColumnsAndData(String sObjectName, List<String> sObjectFieldsNames) {
try{
Map<String, Schema.SObjectField> m = Schema.describeSObjects(sObjectName.split(','))[0].fields.getMap();
List<Object> columns = new List<Object>();
for ( String fieldName: sObjectFieldsNames ) {
Schema.DescribeFieldResult dfr = m.get( fieldName ).getDescribe();
Map<String, Object> column = new Map<String, Object>{
'label' => dfr.getLabel(),
'fieldName' => dfr.getName(),
'type' => String.valueOf( dfr.getType() ).toLowerCase(),
'sortable'=>true
};
columns.add( column );
}
String query = 'SELECT ' + String.join( sObjectFieldsNames, ', ') + ' FROM ' + sObjectName;
List<SObject> records = Database.query( query );
return new Map<String, Object>{
'columns' => columns,
'data' => records
};
}
catch(Exception ex) {
return new MAP<string,object>{'Exception'=>ex.getMessage()};
}
}
}

PaginationComponent.cmp

 <aura:component controller="PaginationHandler" access="global" >
<aura:handler name="init" value="{! this }" action="{! c.init }"/>
<aura:attribute name="sObjectName" type="String" default="Account"/>
<aura:attribute name="sObjectFieldsNames" type="List" default="Name,Type,Industry,AccountNumber,CreatedDate"/>
<aura:attribute name="data" type="Object"/>
<aura:attribute name="columns" type="List"/>
<aura:attribute name="allData" type="List" />
<aura:attribute name="filteredData" type="List" />
<aura:attribute name="pageSize" type="Integer" default="10" />
<aura:attribute name="pageSizeOptions" type="Integer[]" default="10,15,20,25,50,100" />
<aura:attribute name="currentPageNumber" type="Integer" default="1" />
<aura:attribute name="totalPages" type="Integer" default="1" />
<aura:attribute name="searchPhrase" type="String" />
<aura:html tag="style">
.slds-form-element__label{
display:none !important;
}
</aura:html>
<lightning:card>
<div class="slds-p-around_small slds-grid slds-grid_align-spread slds-grid_vertical-align-start">
<div>
<lightning:select label="" value="{! v.pageSize }" onchange="{!c.onPageSizeChange}">
<aura:iteration items="{!v.pageSizeOptions}" var="opt">
<option text="{!opt}"></option>
</aura:iteration>
</lightning:select>
</div>
<div>
<lightning:button label="First" iconName="utility:left" iconPosition="left" onclick="{! c.onFirst }" disabled="{! v.currentPageNumber == 1 }" />
<lightning:button label="Previous" iconName="utility:chevronleft" iconPosition="left" onclick="{! c.onPrev }" disabled="{! v.currentPageNumber == 1 }" />
<span class="slds-var-p-horizontal_x-small"> Page {! (v.currentPageNumber) } of {! (v.totalPages) } </span>
<lightning:button label="Next" iconName="utility:chevronright" iconPosition="right" onclick="{! c.onNext }" disabled="{! v.currentPageNumber == v.totalPages }"/>
<lightning:button label="Last" iconName="utility:right" iconPosition="right" onclick="{! c.onLast }" disabled="{! v.currentPageNumber == v.totalPages }" />
</div>
<div class="inline-container">
<span class="padding-right">
<lightning:input onkeyup="{! c.handleSearch }" variant="label-hidden" placeholder="Search Phrase" type="search" value="{! v.searchPhrase }" onchange="{! c.onChangeSearchPhrase }" />
</span>
</div>
</div>
</lightning:card>
<lightning:datatable data="{! v.data }"
columns="{! v.columns }"
keyField="id"
hideCheckboxColumn="true"/>
</aura:component>

PaginationController.js

 ({
init : function(component, event, helper) {
helper.callActionAsPromise(component,helper,'c.getColumnsAndData',{
'sObjectName': component.get('v.sObjectName'),
'sObjectFieldsNames': component.get('v.sObjectFieldsNames')
})
.then(function(r) {
component.set('v.columns', r.result.columns);
component.set('v.allData', r.result.data);
component.set('v.filteredData', r.result.data);
helper.preparePagination(component, r.result.data);
})
},

onNext: function(component, event, helper) {
let pageNumber = component.get("v.currentPageNumber");
component.set("v.currentPageNumber", pageNumber + 1);
helper.setPageDataAsPerPagination(component);
},

onPrev: function(component, event, helper) {
let pageNumber = component.get("v.currentPageNumber");
component.set("v.currentPageNumber", pageNumber - 1);
helper.setPageDataAsPerPagination(component);
},

onFirst: function(component, event, helper) {
component.set("v.currentPageNumber", 1);
helper.setPageDataAsPerPagination(component);
},

onLast: function(component, event, helper) {
component.set("v.currentPageNumber", component.get("v.totalPages"));
helper.setPageDataAsPerPagination(component);
},

onPageSizeChange: function(component, event, helper) {
helper.preparePagination(component, component.get('v.filteredData'));
},

onChangeSearchPhrase : function (component, event, helper) {
if ($A.util.isEmpty(component.get("v.searchPhrase"))) {
let allData = component.get("v.allData");
component.set("v.filteredData", allData);
helper.preparePagination(component, allData);
}
},

handleSearch : function (component, event, helper) {
helper.searchRecordsBySearchPhrase(component);
},
})
PaginationHelper.js
 ({
callActionAsPromise : function(component, helper, actionName, params) {
return new Promise($A.getCallback(function(resolve, reject) {
let action = component.get(actionName);
action.setParams(params);
action.setCallback(helper, function(actionResult) {
if (actionResult.getState() === 'SUCCESS') {
resolve({'component':component, 'helper':helper, 'result':actionResult.getReturnValue()});
} else {
let errors = actionResult.getError();
reject(new Error(errors && Array.isArray(errors) && errors.length === 1 ? errors[0].message : JSON.stringify(errors)));
}
});
$A.enqueueAction(action);
}));
},

preparePagination: function (component, records) {
let countTotalPage = Math.ceil(records.length/component.get("v.pageSize"));
let totalPage = countTotalPage > 0 ? countTotalPage : 1;
component.set("v.totalPages", totalPage);
component.set("v.currentPageNumber", 1);
this.setPageDataAsPerPagination(component);
},

setPageDataAsPerPagination: function(component) {
let data = [];
let pageNumber = component.get("v.currentPageNumber");
let pageSize = component.get("v.pageSize");
let filteredData = component.get('v.filteredData');
let x = (pageNumber - 1) * pageSize;
for (; x < (pageNumber) * pageSize; x++){
if (filteredData[x]) {
data.push(filteredData[x]);
}
}
component.set("v.data", data);
},

searchRecordsBySearchPhrase : function (component) {
let searchPhrase = component.get("v.searchPhrase");
if (!$A.util.isEmpty(searchPhrase)) {
let allData = component.get("v.allData");
let filteredData = allData.filter(record => record.Name.includes(searchPhrase));
component.set("v.filteredData", filteredData);
this.preparePagination(component, filteredData);
}
},

})

Output:


Hope you like this post, for any feedback or suggestions please feel free to comment. I would appreciate your feedback and suggestions.
Thank you.