Pagination and Searching in Salesforce Lightning Tree Grid

In Salesforce Lightning, the Lightning Tree Grid component offers a powerful way to display hierarchical data with rich features. However, implementing pagination and searching within the Lightning Tree Grid can enhance its usability and efficiency. In this blog post, we'll explore how to master pagination and searching in the Lightning Tree Grid component.

For a detailed implementation guide and examples of Lightning Tree Grid component, you can refer to my blog post titled "Salesforce Lightning Tree Grid: A Comprehensive Guide" available here.

Understanding Pagination

Pagination is a common technique used to divide large datasets into smaller, more manageable chunks or pages. It allows users to navigate through the dataset one page at a time, reducing load times and improving user experience.

In Lightning Web Components (LWC), implementing pagination in a Lightning Tree Grid involves tracking the current page number, total number of pages, and the number of records to display per page. By slicing the dataset based on the current page and page size, we can dynamically update the displayed records as users navigate through the pages.

Searching Functionality

Searching functionality enables users to filter the dataset based on specific criteria, such as a keyword or phrase. This functionality is invaluable when dealing with large datasets, allowing users to quickly find relevant information.

<template>
    <!-- Lightning Card for displaying the Lightning Tree Grid -->
    <lightning-card variant="Narrow" title="Lightning Tree Grid" icon-name="standard:account">
        <div class="slds-p-around_medium">
            <!-- Input field for searching -->
            <lightning-input
                type="search"
                label="Search"
                placeholder="Search by Name"
                onchange={handleSearch}>
            </lightning-input>
            <br />

            <!-- Lightning Tree Grid component -->
            <lightning-tree-grid
                columns={columns}
                data={gridData}
                key-field="Name"
                hide-checkbox-column>
            </lightning-tree-grid>

            <br />
            <!-- Pagination controls -->
            <lightning-layout horizontal-align="space">
                <lightning-layout-item flexibility="auto">
                    <!-- Button for navigating to previous page -->
                    <lightning-button label="Previous" icon-name="utility:chevronleft" onclick={previousHandler}></lightning-button>
                </lightning-layout-item>
                <lightning-layout-item flexibility="auto">
                    <!-- Displaying current page information and total records -->
                    {startingRecord} to {endingRecord} of {totalRecord}. Page {page} of {totalPages}
                </lightning-layout-item>
                <lightning-layout-item flexibility="auto">
                    <!-- Button for navigating to next page -->
                    <lightning-button label="Next" icon-name="utility:chevronright" icon-position="right" onclick={nextHandler}></lightning-button>
                </lightning-layout-item>
            </lightning-layout>
            <br/>
        </div>
    </lightning-card>
</template>
import { LightningElement, wire, track } from 'lwc';
import getAccounts from '@salesforce/apex/getAccountAndContact.getAllAccountsWithContacts';

export default class TreeGridLwc extends LightningElement {
    @track gridData;
    @track page = 1;
    @track totalPages;
    @track startingRecord = 1;
    @track endingRecord;
    @track totalRecord;
    @track pageSize = 5;
    @track items = [];
    @track searchTerm = '';

    @wire(getAccounts)
    accountsWithContact({ data, error }) {
        if (data) {
            this.items = this.formatGridData(data);
            this.filterData();
        } else if (error) {
            console.log("Error:", JSON.stringify(error));
        }
    }

    @track columns = [
        {
            label: "Name",
            fieldName: "Url",
            type: "url",
            typeAttributes:{label:{fieldName:"Name"},target: "_blank"}
        },
        { label: 'Phone', fieldName: 'Phone', type: 'text' },
        { label: 'Website', fieldName: 'Website', type: 'url', typeAttributes: { target: '_blank' } },
    ];


    formatGridData(result) {
        return result.map(item => {
            const { Contacts, ...account } = item;

            // Adding a new custom property to each account
            const formattedAccount = {
                ...account,
                Url: `/${account.Id}` // Custom property for account
            };

            // Ensure Contacts is an array before mapping over it
            const formattedContacts = (Contacts || []).map(contact => ({
                ...contact,
                Url: `/${contact.Id}`, // Custom property for contact
            }));

            return { ...formattedAccount, "_children": formattedContacts };
        });
    }

    ////////////////////////////// Searching //////////////////////////////////////

// Method to handle search input change
handleSearch(event) {
    // Update the search term with the lowercase value of the entered search term
    this.searchTerm = event.target.value.toLowerCase();
    // Apply filtering based on the updated search term
    this.filterData();
}

// Method to filter data based on the search term
filterData() {
    // Filter items array to include only items whose name matches the search term
    let filteredItems = this.items.filter(item => {
        return item.Name.toLowerCase().includes(this.searchTerm);
    });
    // Update total record count based on the filtered items
    this.totalRecord = filteredItems.length;
    // Calculate total pages based on the total record count and page size
    this.totalPages = Math.ceil(this.totalRecord / this.pageSize);
    // Reset pagination to the first page of search results and display records accordingly
    this.displayRecordPerPage(1, filteredItems);
}

////////////////////////////// Pagination //////////////////////////////////////

// Method to navigate to the previous page
previousHandler(event) {
    // Check if the current page is greater than 1
    if (this.page > 1) {
        // Decrement the current page
        this.page = this.page - 1;
        // Update displayed records for the previous page
        this.displayRecordPerPage(this.page);
    }
}

// Method to navigate to the next page
nextHandler(event) {
    // Check if the current page is less than the total pages
    if (this.page < this.totalPages) {
        // Increment the current page
        this.page = this.page + 1;
        // Update displayed records for the next page
        this.displayRecordPerPage(this.page);
    }
}

// Method to display records for the specified page
displayRecordPerPage(page, itemsToDisplay = this.items) {
    // Set the current page
    this.page = page;
    // Calculate the starting and ending record indices for the specified page
    this.startingRecord = (page - 1) * this.pageSize + 1;
    this.endingRecord = page * this.pageSize;
    // Ensure the ending record index does not exceed the total record count
    this.endingRecord = this.endingRecord > this.totalRecord ? this.totalRecord : this.endingRecord;
    // Update the gridData with the records to be displayed for the specified page
    this.gridData = itemsToDisplay.slice(this.startingRecord - 1, this.endingRecord);
}

}

Conclusion

Navigating data seamlessly through pagination and searching in the Lightning Tree Grid empowers users to efficiently explore and interact with hierarchical data. By understanding and implementing these functionalities effectively, developers can create Lightning components that offer enhanced usability and provide a seamless user experience.