
Custom Data Table With Pagination And Checkbox Functionality In Salesforce Lightning
Hello guys, today in this post we are going to learn how we can create custom lightning data table with client side JavaScript pagination buttons and row level checkbox functionality using salesforce lightning component. In this component we’ll also persist checkbox checked state on pagination.
Component Features Highlights :
- Client Side JavaScript Pagination.
- Inline Checkbox Functionality.
- Get Selected Rows in Controller.
- Total Records Count
- Selected Records Count
- Select/Deselect All Checkbox

Apex Controller : dataTableCtrl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/* API : 49.00 Author : Rahul Joshi Source : sfdcMonkey.com Date : Dec,2020 */ public class dataTableCtrl{ @AuraEnabled public static List<accountListWrapper> fetchAccountWrapper(){ List<accountListWrapper> lstaccountListWrapper = new List<accountListWrapper>(); // query account records and create 'accountListWrapper' class instance for each record. for(Account acc : [Select id,Name,Type,Phone From Account Limit 1000]){ // by default checkbox should be false lstaccountListWrapper.add(new accountListWrapper(false,acc)); } // return the 'lstaccountListWrapper' list return lstaccountListWrapper; } /* wrapper class */ public class accountListWrapper { @AuraEnabled public boolean isChecked {get;set;} @AuraEnabled public account objAccount{get;set;} public accountListWrapper(boolean isChecked, account objAccount){ this.isChecked = isChecked; this.objAccount = objAccount; } } } |
- Check code comments.
Lightning Component : tableWithPC.cmp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
<!-- API : 49.00 Author : Rahul Joshi Source : sfdcMonkey.com Date : Dec,2020 --> <aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global" controller="dataTableCtrl"> <!-- call doInit method on component load --> <aura:handler name="init" value="{!this}" action="{!c.doInit}"/> <!-- aura attributes to store data/values --> <aura:attribute name="listOfAllAccounts" type="list"/> <aura:attribute name="PaginationList" type="list"/> <aura:attribute name="selectedCount" type="integer" default="0" description="selected Records Count"/> <aura:attribute name="startPage" type="Integer" /> <aura:attribute name="endPage" type="Integer"/> <aura:attribute name="totalRecordsCount" type="Integer"/> <aura:attribute name="pageSize" type="Integer" default="4" description="number of records to be display on per page"/> <aura:attribute name="currentPage" type="integer" default="1"/> <aura:attribute name="totalPagesCount" type="integer"/> <aura:attribute name="bNoRecordsFound" type="boolean"/> <aura:if isTrue="{!v.bNoRecordsFound}"> <!--display error message if there is no records available --> <div class="slds-notify slds-notify_alert slds-theme_alert-texture slds-theme_info" role="alert"> <span class="slds-assistive-text">error</span> <h2>No record found.</h2> </div> <aura:set attribute="else"> <!-- lightning:button to get selected rows data --> <div class="slds-clearfix slds-m-around_small"> <div class="slds-clearfix"> <div class="slds-float_right"> <lightning:button variant="destructive" label="Get Selected Records" onclick="{! c.getSelectedRecords }" disabled="{!v.selectedCount == 0}"/> </div> </div> </div> <!-- display total record and selected record count --> <p class="slds-m-around_small"> <span class="slds-badge slds-badge_lightest" style="display:inline-block"> Total Records : {!v.selectedCount > 0 ? v.selectedCount + '/' : ''} {!v.totalRecordsCount} </span> </p> <!-- data table start--> <table class="slds-table slds-table_bordered slds-table_cell-buffer"> <thead> <tr class="slds-text-title_caps"> <!--header checkbox for select all--> <th style="width:3.25rem;" class="slds-text-align_right"> <div class="slds-form-element"> <div class="slds-form-element__control"> <label class="slds-checkbox"> <ui:inputCheckbox disabled="{!v.totalRecordsCount == 0}" aura:id="selectAllId" change="{!c.selectAllCheckbox}"/> <span class="slds-checkbox_faux"></span> <span class="slds-form-element__label"></span> </label> </div> </div> </th> <th scope="col"> <div class="slds-truncate" title="Name">Name</div> </th> <th scope="col"> <div class="slds-truncate" title="Phone">Phone</div> </th> <th scope="col"> <div class="slds-truncate" title="Type">Type</div> </th> </tr> </thead> <tbody> <aura:iteration items="{!v.PaginationList}" var="obj"> <tr> <th scope="row" class="slds-text-align_right" style="width:3.25rem;"> <div class="slds-form-element"> <div class="slds-form-element__control"> <label class="slds-checkbox"> <ui:inputCheckbox text="{!obj.objAccount.Id}" value="{!obj.isChecked}" change="{!c.checkboxSelect}"/> <span class="slds-checkbox_faux"></span> <span class="slds-form-element__label text"></span> </label> </div> </div> </th> <th scope="row"> <div class="slds-truncate" title="{!obj.objAccount.Name}"> {!obj.objAccount.Name} </div> </th> <th scope="row"> <div class="slds-truncate" title="{!obj.objAccount.Phone}"> <lightning:formattedPhone value="{!obj.objAccount.Phone}"/> </div> </th> <th scope="row"> <div class="slds-truncate" title="{!obj.objAccount.Type}"> {!obj.objAccount.Type} </div> </th> </tr> </aura:iteration> </tbody> </table> <!-- DataTable End --> <br/> <!-- Pagination Buttons Start --> <div class="slds-align_absolute-center"> <lightning:button label="Previous" disabled="{!v.startPage == 0}" onclick="{!c.navigation}" variant="brand" iconName="utility:back" name="previous"/> <span class="slds-badge slds-badge_lightest" style="margin-right: 10px;margin-left: 10px;"> Page {!v.currentPage} out of {!v.totalPagesCount} </span> <lightning:button label="Next" disabled="{!(v.endPage + 1) >= v.totalRecordsCount}" onclick="{!c.navigation}" variant="brand" iconName="utility:forward" iconPosition="right" name="next"/> </div> <!-- Pagination Buttons End --> </aura:set> </aura:if> </aura:component> |
- Check code comments.
JavaScript Controller : tableWithPCController.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
({ doInit: function(component, event, helper) { helper.doInitHelper(component, event); }, /* javaScript function for pagination */ navigation: function(component, event, helper) { var sObjectList = component.get("v.listOfAllAccounts"); var end = component.get("v.endPage"); var start = component.get("v.startPage"); var pageSize = component.get("v.pageSize"); var whichBtn = event.getSource().get("v.name"); // check if whichBtn value is 'next' then call 'next' helper method if (whichBtn == 'next') { component.set("v.currentPage", component.get("v.currentPage") + 1); helper.next(component, event, sObjectList, end, start, pageSize); } // check if whichBtn value is 'previous' then call 'previous' helper method else if (whichBtn == 'previous') { component.set("v.currentPage", component.get("v.currentPage") - 1); helper.previous(component, event, sObjectList, end, start, pageSize); } }, selectAllCheckbox: function(component, event, helper) { var selectedHeaderCheck = event.getSource().get("v.value"); var updatedAllRecords = []; var updatedPaginationList = []; var listOfAllAccounts = component.get("v.listOfAllAccounts"); var PaginationList = component.get("v.PaginationList"); // play a for loop on all records list for (var i = 0; i < listOfAllAccounts.length; i++) { // check if header checkbox is 'true' then update all checkbox with true and update selected records count // else update all records with false and set selectedCount with 0 if (selectedHeaderCheck == true) { listOfAllAccounts[i].isChecked = true; component.set("v.selectedCount", listOfAllAccounts.length); } else { listOfAllAccounts[i].isChecked = false; component.set("v.selectedCount", 0); } updatedAllRecords.push(listOfAllAccounts[i]); } // update the checkbox for 'PaginationList' based on header checbox for (var i = 0; i < PaginationList.length; i++) { if (selectedHeaderCheck == true) { PaginationList[i].isChecked = true; } else { PaginationList[i].isChecked = false; } updatedPaginationList.push(PaginationList[i]); } component.set("v.listOfAllAccounts", updatedAllRecords); component.set("v.PaginationList", updatedPaginationList); }, checkboxSelect: function(component, event, helper) { // on each checkbox selection update the selected record count var selectedRec = event.getSource().get("v.value"); var getSelectedNumber = component.get("v.selectedCount"); if (selectedRec == true) { getSelectedNumber++; } else { getSelectedNumber--; component.find("selectAllId").set("v.value", false); } component.set("v.selectedCount", getSelectedNumber); // if all checkboxes are checked then set header checkbox with true if (getSelectedNumber == component.get("v.totalRecordsCount")) { component.find("selectAllId").set("v.value", true); } }, getSelectedRecords: function(component, event, helper) { var allRecords = component.get("v.listOfAllAccounts"); var selectedRecords = []; for (var i = 0; i < allRecords.length; i++) { if (allRecords[i].isChecked) { selectedRecords.push(allRecords[i].objAccount); } } alert(JSON.stringify(selectedRecords)); } }) |
- check code comments
JavaScript Helper : tableWithPCHelper.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
({ /* doInitHelper funcation to fetch all records, and set attributes value on component load */ doInitHelper : function(component,event){ var action = component.get("c.fetchAccountWrapper"); action.setCallback(this, function(response) { var state = response.getState(); if (state === "SUCCESS"){ var oRes = response.getReturnValue(); if(oRes.length > 0){ component.set('v.listOfAllAccounts', oRes); var pageSize = component.get("v.pageSize"); var totalRecordsList = oRes; var totalLength = totalRecordsList.length ; component.set("v.totalRecordsCount", totalLength); component.set("v.startPage",0); component.set("v.endPage",pageSize-1); var PaginationLst = []; for(var i=0; i < pageSize; i++){ if(component.get("v.listOfAllAccounts").length > i){ PaginationLst.push(oRes[i]); } } component.set('v.PaginationList', PaginationLst); component.set("v.selectedCount" , 0); //use Math.ceil() to Round a number upward to its nearest integer component.set("v.totalPagesCount", Math.ceil(totalLength / pageSize)); }else{ // if there is no records then display message component.set("v.bNoRecordsFound" , true); } } else{ alert('Error...'); } }); $A.enqueueAction(action); }, // navigate to next pagination record set next : function(component,event,sObjectList,end,start,pageSize){ var Paginationlist = []; var counter = 0; for(var i = end + 1; i < end + pageSize + 1; i++){ if(sObjectList.length > i){ if(component.find("selectAllId").get("v.value")){ Paginationlist.push(sObjectList[i]); }else{ Paginationlist.push(sObjectList[i]); } } counter ++ ; } start = start + counter; end = end + counter; component.set("v.startPage",start); component.set("v.endPage",end); component.set('v.PaginationList', Paginationlist); }, // navigate to previous pagination record set previous : function(component,event,sObjectList,end,start,pageSize){ var Paginationlist = []; var counter = 0; for(var i= start-pageSize; i < start ; i++){ if(i > -1){ if(component.find("selectAllId").get("v.value")){ Paginationlist.push(sObjectList[i]); }else{ Paginationlist.push(sObjectList[i]); } counter ++; }else{ start++; } } start = start - counter; end = end - counter; component.set("v.startPage",start); component.set("v.endPage",end); component.set('v.PaginationList', Paginationlist); }, }) |
- Check code comments.
Test App :
1 2 3 4 5 6 7 8 |
<aura:application extends="force:slds"> <c:tableWithPC/> <!-- here c: is org. default namespace prefix--> </aura:application> |
Output :

Other popular Post :
- How To Use jQuery DataTable Plugin In Salesforce Lightning Component -: Sample
- Powerful Lightning Datatable base component – Example Using Fieldset
- Custom Data Table With Inline Editing In Salesforce Lightning Component – Sample
- Add Delete Row Dynamic In Lightning Component : Sample Code
- Add Multiple Child Records to Parent Object With Lightning Component
Like our facebook page for new post updates. & Don’t forget to bookmark this site for your future reference.
Happy Learning 🙂