Building Interactive Data Tables in Salesforce Lightning Web Components

In Salesforce Lightning Web Components (LWC), displaying data in a visually appealing and interactive manner is crucial for enhancing user experience. One common requirement is to present data in a tabular format, allowing users to easily navigate, view details, and perform actions on individual records. In this blog post, we'll explore how to build a dynamic data table in LWC, fetch data from Salesforce, and incorporate interactive features like row navigation and map viewing.

Fetching Data

The first step in building our data table is to fetch the necessary data from Salesforce. We achieve this using Apex, Salesforce's server-side language. In our example, we have a simple Apex method getAccounts() that queries a list of accounts with specific fields.

public with sharing class AccountController {
    // Apex method to fetch accounts
    @AuraEnabled(cacheable=true)
    public static List<Account> getAccounts() {
        // Query to fetch accounts with specific fields
        return [SELECT Id, Name, Industry, AnnualRevenue, Phone, BillingStreet, BillingCity, BillingState, BillingPostalCode, BillingCountry FROM Account LIMIT 10];
    }
}

Constructing the Data Table and Modal

<template>
    <!-- Account List Card -->
    <div if:true={showsearchscreen}>
        <lightning-card title="Account List">
            <div class="slds-m-around_medium">
                <!-- Lightning Data Table -->
                <lightning-datatable
                    key-field="Id"
                    data={accounts}
                    columns={columns}
                    onrowaction={handleRowAction}
                    hide-checkbox-column="true">
                </lightning-datatable>
            </div>
        </lightning-card>
    </div>

    <!-- Modal Section -->
    <template if:true={isModalOpen}>
        <!-- Backdrop to blur the background -->
        <div class="slds-backdrop slds-backdrop_open"></div>    
        <!-- Modal Dialog -->
        <section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open slds-modal_large" >
            <div class="slds-modal__container" style="width:50%;">
                <!-- Modal Header -->
                <header class="slds-modal__header">
                    <!-- Close Button -->
                    <button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse" onclick={closeModal} title="Close">
                        <lightning-icon icon-name="utility:close" size="medium" variant="inverse"></lightning-icon>
                        <span class="slds-assistive-text">Close</span>
                    </button>
                    <!-- Modal Title -->
                    <h2 class="slds-text-heading_medium slds-hyphenate" style="color: black;">Account Address Details</h2>
                </header>
                <!-- Modal Content -->
                <div class="slds-modal__content" id="modal-content-id-1">
                    <!-- Address details and map -->
                    <div class="slds-grid slds-wrap">
                        <!-- Address details (left side) -->
                        <div class="slds-col slds-size_1-of-3" style="padding: 1rem;">
                            <p>Address:</p>
                            <p>{selectedAccount.BillingStreet}</p>
                            <p>{selectedAccount.BillingCity}, {selectedAccount.BillingState}</p>
                            <p>{selectedAccount.BillingPostalCode}</p>
                            <p>{selectedAccount.BillingCountry}</p>
                        </div>
                        <!-- Map (right side) -->
                        <div class="slds-col slds-size_2-of-3" style="padding: 1rem;">
                            <lightning-map map-markers={mapMarkers}></lightning-map>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </template>
</template>

Enhancing Interactivity

To add interactivity to our data table, we implement features like row navigation and viewing address details on a map. By handling row actions, such as clicking the "View" button, we can open a modal that displays the selected account's address and a map marker for its location.

// Import necessary modules from LWC and Salesforce
import { LightningElement, wire } from 'lwc';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';


// Define the row actions for the data table
const actions = [
    { label: 'View on Map', name: 'View' }
];

// Define the columns for the data table
const columns = [

    {
        label: "Name",
        fieldName: "AssignedToNameUrl",
        type: "url",
        typeAttributes:{label:{fieldName:"AssignedToName"},target: "_blank"}
    },
    { label: 'Industry', fieldName: 'Industry', type: 'text' },
    { label: 'Phone', fieldName: 'Phone', type: 'phone' },
    { label: 'Street', fieldName: 'BillingStreet', type: 'text' },
    { label: 'City', fieldName: 'BillingCity', type: 'text' },
    { label: 'State', fieldName: 'BillingState', type: 'text' },
    { label: 'Postal Code', fieldName: 'BillingPostalCode', type: 'text' },
    { label: 'Country', fieldName: 'BillingCountry', type: 'text' },
    {
        type: 'action',
        typeAttributes: { rowActions: actions, menuAlignment: 'right' }
    }
];

// Export the default class for the LWC component
export default class DataTableLwc extends LightningElement  {
    // Define properties
    columns = columns; // Define the columns for the data table
    accounts = []; // Initialize accounts array to store fetched accounts
    isModalOpen = false; // Flag to control the visibility of the modal
    showsearchscreen = false; // Flag to control the visibility of the search screen

    // Wire the Apex method to fetch accounts
    @wire(getAccounts)
    wiredAccounts({ error, data }) {
        if (data) {
            // If data is available, set showsearchscreen to true
            this.showsearchscreen = true;
            // Map the fetched accounts and format the AnnualRevenue
            this.accounts = this.TransformWireData(data);
        } else if (error) {
            // Log an error if encountered while fetching accounts
            console.error('Error loading accounts', error);
        }
    }

    // Function to transform the data fetched from Apex
    TransformWireData(response) {
        return response.map((data) => {
            // Construct URL for the account name
            const assignedToNameUrl = `/${data.Id}`;
            const assignedToName = data.Name;

            // Return transformed data with URL and name
            return {
                ...data,
                AssignedToNameUrl :assignedToNameUrl,
                AssignedToName : assignedToName
            };
        });
    }

    // Handle row actions (e.g., View on Map)
    handleRowAction(event) {
        const actionName = event.detail.action.name;
        if (actionName === 'View') {
            // If View action is triggered, prepare map markers and open the modal
            this.selectedAccount = event.detail.row;
            this.mapMarkers = [{
                location: {
                    Street: this.selectedAccount.BillingStreet,
                    City: this.selectedAccount.BillingCity,
                    State: this.selectedAccount.BillingState,
                    PostalCode: this.selectedAccount.BillingPostalCode,
                    Country: this.selectedAccount.BillingCountry
                },
                title: this.selectedAccount.Name,
                description: this.selectedAccount.Industry
            }];
            this.isModalOpen = true;
        }
    }

    // Close the modal
    closeModal() {
        this.isModalOpen = false;
    }
}

Conclusion

Building interactive data tables in Salesforce Lightning Web Components allows us to present data effectively and provide a seamless user experience. By leveraging the power of Apex for data retrieval and combining it with LWC's component architecture, we can create rich and engaging interfaces for users to interact with their Salesforce data.