Thursday 8 April 2021

Salesforce Lightning TreeGrid with pagination

INTRODUCTION/SCENARIO

While working on one of the user stories of Pharma sector for a client based on Chicago, USA; there was a requirement to display Contact records under their parent account record. Also, pagination was needed with a picklist to choose number of records to be displayed on a page.

CHALLENGE

Lightning:treeGrid is useful component for displaying structured data such as hierarchy or forecasting data while dealing with the same object. But there is no functionality available to display records of 2 different objects (In our case, Account and Contact) in the same table while using Lightning:treeGrid.

APPROACH / SOLUTION

To overcome this limitation, I've implemented custom Javascript in the lightning component containing the mechanism to have customized list of Accounts and Contacts with pagination.

Note: This component requires API version 42.0 and later.

treeGridController is a controller class of the lightning components treeGrid utilized to fetch Account object data which has having child Contact records.

treeGridController.apxc
public class treeGridController {
    
    @AuraEnabled
    public static List <Account> getAccountList() {
        return [Select Id, Name,
                    (SELECT Name, Phone, Email FROM Contacts) 
                    From Account
                    Where Id IN (Select AccountId From Contact)
                    ORDER BY Name ASC];
    }
}

Below are Component & JavaScript files for the reference which i've used to meet the requirement..

treeGrid.cmp
<aura:component controller="treeGridController" implements="flexipage:availableForAllPageTypes" >
    <aura:attribute name="resultData" type="Object" access="private"/>
    <aura:attribute name="gridColumns" type="List" />
    <aura:attribute name="gridData" type="Object" />
    <aura:attribute name="gridExpandedRows" type="Object" />
    <aura:attribute name="PageNumber" type="Integer" />
    <aura:attribute name="TotalPages" type="Integer"/>
    <aura:attribute name="currentPage" type="Integer" default="0" />
    <aura:attribute name="limit" type="Integer" default="5" />
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <div class="slds-page-header" role="banner">
        <ui:inputSelect aura:id="pageSize" label="Display Records Per Page: " change="{!c.onSelectChange}">
            <ui:inputSelectOption label="5" text="5" value="true"/>
            <ui:inputSelectOption label="10" text="10"/>
            <ui:inputSelectOption label="50" text="50"/>
        </ui:inputSelect>
    </div>
    <lightning:treeGrid aura:id="accTree"
                        columns="{!v.gridColumns}"
                        data="{!v.gridData}"
                        expandedRows="{!v.gridExpandedRows}"
                        keyField="Id"
                        hideCheckboxColumn = "true"
                        />
    <div class="slds-clearfix">
        <div class="slds-page-header" role="banner">
            <div class="slds-float_right">            
                <lightning:button disabled="{!v.PageNumber == 1}" variant="brand" aura:id="prevPage" label="Prev" onclick="{!c.handlePrev}" />            
                <lightning:button disabled="{!v.PageNumber == v.TotalPages}" aura:id="nextPage" variant="brand" label="Next" onclick="{!c.handleNext}"/>
            </div>
            <p class="slds-page-header__title">Page {!v.PageNumber} of {!v.TotalPages}</p>
        </div>
    </div>
</aura:component>

treeGridController.js
({
    doInit : function(component, event, helper) {
        var columns = [
            {
                type: 'url',
                fieldName: 'AccountURL',
                label: 'Account Name',
                typeAttributes: {
                    label: { fieldName: 'accountName' }
                }
            },
            {
                type: 'text',
                fieldName: 'Name',
                label: 'Contact Name'
            },
            {
                type: 'phone',
                fieldName: 'Phone',
                label: 'Phone Number'
            },
            {
                type: 'email',
                fieldName: 'Email',
                label: 'Email'
            }
        ];
        component.set('v.gridColumns', columns);
        var action = component.get("c.getAccountList");
        action.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS" ) {
                var resultData = response.getReturnValue();
                component.set('v.resultData', resultData);
                helper.bindTableData(component, event);
            }
        });
        $A.enqueueAction(action);
    },
    handleNext : function(component, event, helper){
        component.set('v.currentPage',component.get('v.currentPage')+1);
        helper.buildTable(component, event);
    },
    handlePrev : function(component, event, helper){
        component.set('v.currentPage',component.get('v.currentPage')-1);
        helper.buildTable(component, event);
    },
    onSelectChange : function(component, event, helper){
        component.set('v.currentPage',0);
        var pageSize = component.find('pageSize').get('v.value');
        component.set('v.limit',pageSize);
        helper.buildTable(component, event);
    }
})

treeGridHelper.js
({
    bindTableData : function(component, event) {
        var resultData = component.get('v.resultData');
        for (var i=0; i<resultData.length; i++ ) {
            resultData[i].accountName = resultData[i]['Name'];
            delete resultData[i]['Name'];
            resultData[i]._children = resultData[i]['Contacts'];
            delete resultData[i].Contacts;
            resultData[i].AccountURL = '/'+resultData[i].Id;                
        }
        component.set('v.resultData',resultData);
        this.buildTable(component, event);
    },
    buildTable : function(component, event){
        var resultData = component.get('v.resultData');
        var limit = component.get('v.limit');
        var currentPage = component.get('v.currentPage');
        var totalPage = Math.ceil(resultData.length / limit);
        var startIndex = currentPage * limit;
        var row = [];
        var expandedRows = [];        
        for (var i = startIndex; i < parseInt(startIndex)+parseInt(limit); i++) {
            if(resultData[i]){
                expandedRows.push(resultData[i].Id);
                row.push(resultData[i]);
            }
        }
        component.set('v.gridData', row);
        component.set('v.PageNumber',currentPage+1);
        component.set('v.TotalPages',totalPage);
        component.set('v.gridExpandedRows', expandedRows);
    }
})

OUTPUT: 


If you have any questions you can reach out our Salesforce Consulting team here.

No comments:

Post a Comment