Hello Guys,
As we have seen Salesforce recently published a very very important development feature/platform called 'Lightning Web Components'. If you are new to these, I have a sample Pagination implementation example which will try to cover some of the use cases in Lightning web components.
Let's begin with our journey to Pagination. :)
Let's begin with our journey to Pagination. :)
- Create a component called paginatorBottom. This component will have the buttons for the pagination such as Previous, Next, First, Last. This component will fire events on the button actions which will be caught by the parent components.
paginatorBottom.html
<template>
<lightning-layout>
<lightning-layout-item>
<lightning-button label="First" icon-name="utility:chevronleft" onclick={handleFirst}
disabled={showFirstButton}></lightning-button>
</lightning-layout-item>
<lightning-layout-item>
<lightning-button label="Previous" icon-name="utility:chevronleft" onclick={handlePrevious}
disabled={showFirstButton}></lightning-button>
</lightning-layout-item>
<lightning-layout-item flexibility="grow"></lightning-layout-item>
<lightning-layout-item>
<lightning-button label="Next" icon-name="utility:chevronright" icon-position="right" onclick={handleNext}
disabled={showLastButton}></lightning-button>
</lightning-layout-item>
<lightning-layout-item>
<lightning-button label="Last" icon-name="utility:chevronright" icon-position="right" onclick={handleLast}
disabled={showLastButton}></lightning-button>
</lightning-layout-item>
</lightning-layout>
</template>
paginatorBottom.js
import { LightningElement, api } from 'lwc';
export default class PaginatorBottom extends LightningElement {
// Api considered as a reactive public property.
@api totalrecords;
@api currentpage;
@api pagesize;
// Following are the private properties to a class.
lastpage = false;
firstpage = false;
// getter
get showFirstButton() {
if (this.currentpage === 1) {
return true;
}
return false;
}
// getter
get showLastButton() {
if (Math.ceil(this.totalrecords / this.pagesize) === this.currentpage) {
return true;
}
return false;
}
//Fire events based on the button actions
handlePrevious() {
this.dispatchEvent(new CustomEvent('previous'));
}
handleNext() {
this.dispatchEvent(new CustomEvent('next'));
}
handleFirst() {
this.dispatchEvent(new CustomEvent('first'));
}
handleLast() {
this.dispatchEvent(new CustomEvent('last'));
}
}
- Create a Lightning Web component called as a recordList. This component will fetch the records from the Apex class by calling the method. This component will give us information about the Total number of records, Total pages, Accounts data.
- We can see that the recordList.js will have the chaining of the apex method calls(First record count method call then retrieve actual data method call). I intentionally added chaining to showcase how it works.
- This component also has the Search functionality. It showcases the usage of standard renderedCallback function and how to avoid the recursive of infinite calls. Ex. isSearchChangeExecuted variable.
recordList.html
<template>
<lightning-card title="Accounts List" icon-name="custom:custom63">
<div class="slds-m-around_medium">
<lightning-input type="search" onchange={handleKeyChange} class="slds-m-bottom_small" label="Search"
value={searchKey}></lightning-input>
<template if:true={accounts}>
<table
class="slds-table slds-table_bordered slds-table_striped slds-table_cell-buffer slds-table_fixed-layout">
<thead>
<tr class="slds-text-heading_label">
<th scope="col">
<div class="slds-truncate" title="ID">ID</div>
</th>
<th scope="col">
<div class="slds-truncate" title="Name">Name</div>
</th>
</tr>
</thead>
<tbody>
<!-- Use the Apex model and controller to fetch server side data -->
<template for:each={accounts} for:item="account">
<tr key={account.Id}>
<th scope="row">
<div class="slds-truncate" title={account.Id}>{account.Id}</div>
</th>
<td>
<div class="slds-truncate" title={account.Name}>{account.Name}</div>
</td>
</tr>
</template>
</tbody>
</table>
</template>
</div>
<p class="slds-m-vertical_medium content">Total records: <b>{totalrecords} </b> Page <b>{currentpage}</b> of
<b> {totalpages}</b></p>
</lightning-card>
</template>
recordList.js
import { LightningElement, track, api } from 'lwc';
import getAccountsList from '@salesforce/apex/ManageRecordsController.getAccountsList';
import getAccountsCount from '@salesforce/apex/ManageRecordsController.getAccountsCount';
export default class RecordList extends LightningElement {
@track accounts;
@track error;
@api currentpage;
@api pagesize;
@track searchKey;
totalpages;
localCurrentPage = null;
isSearchChangeExecuted = false;
// not yet implemented
pageSizeOptions =
[
{ label: '5', value: 5 },
{ label: '10', value: 10 },
{ label: '25', value: 25 },
{ label: '50', value: 50 },
{ label: 'All', value: '' },
];
handleKeyChange(event) {
if (this.searchKey !== event.target.value) {
this.isSearchChangeExecuted = false;
this.searchKey = event.target.value;
this.currentpage = 1;
}
}
renderedCallback() {
// This line added to avoid duplicate/multiple executions of this code.
if (this.isSearchChangeExecuted && (this.localCurrentPage === this.currentpage)) {
return;
}
this.isSearchChangeExecuted = true;
this.localCurrentPage = this.currentpage;
getAccountsCount({ searchString: this.searchKey })
.then(recordsCount => {
this.totalrecords = recordsCount;
if (recordsCount !== 0 && !isNaN(recordsCount)) {
this.totalpages = Math.ceil(recordsCount / this.pagesize);
getAccountsList({ pagenumber: this.currentpage, numberOfRecords: recordsCount, pageSize: this.pagesize, searchString: this.searchKey })
.then(accountList => {
this.accounts = accountList;
this.error = undefined;
})
.catch(error => {
this.error = error;
this.accounts = undefined;
});
} else {
this.accounts = [];
this.totalpages = 1;
this.totalrecords = 0;
}
const event = new CustomEvent('recordsload', {
detail: recordsCount
});
this.dispatchEvent(event);
})
.catch(error => {
this.error = error;
this.totalrecords = undefined;
});
}
}
- Now we will create a parent component which will include both these components.
- This component will handle the events fired by buttons.
paginationParent.html
<template>
<lightning-card>
<c-record-list currentpage={page} onrecordsload={handleRecordsLoad} pagesize={pagesize}></c-record-list>
<div class="slds-m-around_medium">
<c-paginator-bottom onprevious={handlePrevious} onnext={handleNext} onfirst={handleFirst}
onlast={handleLast} currentpage={page} totalrecords={totalrecords} pagesize={pagesize}>
</c-paginator-bottom>
</div>
</lightning-card>
</template>
paginationParent.js
import { LightningElement, track, api } from 'lwc';
const PAGE_SIZE = 5;
export default class PaginationParent extends LightningElement {
@api page = 1;
@api totalrecords;
@api _pagesize = PAGE_SIZE;
get pagesize() {
return this._pagesize;
}
set pagesize(value) {
this._pagesize = value;
}
handlePrevious() {
if (this.page > 1) {
this.page = this.page - 1;
}
}
handleNext() {
if (this.page < this.totalPages)
this.page = this.page + 1;
}
handleFirst() {
this.page = 1;
}
handleLast() {
this.page = this.totalPages;
}
handleRecordsLoad(event) {
this.totalrecords = event.detail;
this.totalPages = Math.ceil(this.totalrecords / this.pagesize);
}
handlePageChange(event) {
this.page = event.detail;
}
}
Now finally create Apex class ManageRecordsController, which will give us the required information such as record count, account list.
Note: We have intentionally created separate methods for record count and account list, to showcase the chaining of the Apex method calls.
ManageRecordsController.cls
public with sharing class ManageRecordsController {
@AuraEnabled(cacheable = true)
public static List<Account> getAccountsList(Integer pagenumber, Integer numberOfRecords, Integer pageSize, String searchString) {
String searchKey = '%' + searchString + '%';
String query = 'select id, Name from Account ';
if (searchString != null && searchString != '') {
query += ' where name like \'%' + searchString + '%\' ';
}
query += ' limit ' + pageSize + ' offset ' + (pageSize * (pagenumber - 1));
return Database.query(query);
}
@AuraEnabled(cacheable = true)
public static Integer getAccountsCount(String searchString) {
String query = 'select count() from Account ';
if (searchString != null && searchString != '') {
query += ' where name like \'%' + searchString + '%\' ';
}
return Database.countQuery(query);
}
}
We are ready with our pagination Lightning Web Component implementation. You can include this component anywhere.
Example
<template>
<c-pagination-bar></c-pagination-bar>
</template>
And don't forget to include following lines in the meta.xml file, in case you wanna expose this pagination on App/Record/Hope page.
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>45.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>








No comments:
Post a Comment