Expandable Table Rows in Salesforce LWC

Expandable Table Rows in Salesforce LWC

Sample Code:

Apex Class:

public with sharing class AccountController {
 
    @AuraEnabled( cacheable = true )
    public static List< AccountWrapper > fetchAccounts() {
     
        List< AccountWrapper > listWrap = new List< AccountWrapper >();
        
        for ( Account objAcc : [ SELECT Id, Name, Industry, AccountNumber, Rating, Type,  
                                        ( SELECT Id, FirstName, LastName, Email FROM Contacts )
                                   FROM Account
                                  LIMIT 10 ] ) {
            
            AccountWrapper objWrap = new AccountWrapper( true, objAcc, objAcc.Contacts.size() > 0 ? true : false );
            listWrap.add( objWrap );

        }

        return listWrap;
         
    }

    public class AccountWrapper {

        @AuraEnabled
        public Boolean hideBool;
        @AuraEnabled
        public Boolean contactBool;
        @AuraEnabled
        public Account objAccount;

        public AccountWrapper( Boolean hideBool, Account objAccount, Boolean contactBool ) {

            this.hideBool = hideBool;
            this.objAccount = objAccount;
            this.contactBool = contactBool;

        }

    }
     
}

Lightning Web Component:

HTML:

<template>
    <div class="slds-box slds-theme--default">
        <div class="slds-text-color_inverse slds-text-heading_large" style="padding:0.5rem;background:#16325c">        
            Accounts
        </div>
        <div style="padding:2px;">
            <lightning-button variant="brand" label="Expand All" onclick={expandAll} class="slds-m-left_x-small"></lightning-button>
            <lightning-button variant="brand" label="Collapse All" onclick={collapseAll} class="slds-m-left_x-small"></lightning-button>
        </div>
        <table class="slds-table slds-table_cell-buffer slds-table_bordered slds-table_striped">
            <thead>
                <tr class="slds-line-height_reset">
                    <th>
                        Account Name
                    </th>
                    <th>
                        Account Number
                    </th>
                    <th>
                        Industry
                    </th>
                    <th>
                        Rating
                    </th>
                    <th>
                        Type
                    </th>
                </tr>
            </thead>
            <tbody>
                <template iterator:it={records}>
                    <tr class="slds-hint-parent" key={it.value.objAccount.Id} style="cursor: pointer;">                        
                        <td data-label="Account Name">       
                            <a href="#" onclick={hideAndShow} data-record-id={it.index} style="display:block;text-decoration:none;color:black;">                 
                                {it.value.objAccount.Name}
                            </a>
                        </td>
                        <td data-label="Account Number">
                            <a href="#" onclick={hideAndShow} data-record-id={it.index} style="display:block;text-decoration:none;color:black;">                 
                                {it.value.objAccount.AccountNumber}
                            </a>
                        </td>
                        <td data-label="Industry">
                            <a href="#" onclick={hideAndShow} data-record-id={it.index} style="display:block;text-decoration:none;color:black;">                 
                                {it.value.objAccount.Industry}
                            </a>
                        </td>
                        <td data-label="Rating">
                            <a href="#" onclick={hideAndShow} data-record-id={it.index} style="display:block;text-decoration:none;color:black;">                 
                                {it.value.objAccount.Rating}
                            </a>
                        </td>
                        <td data-label="Type">
                            <a href="#" onclick={hideAndShow} data-record-id={it.index} style="display:block;text-decoration:none;color:black;">                 
                                {it.value.objAccount.Type}
                            </a>
                        </td>    
                    </tr>
                    <template if:false={it.value.hideBool} key={it.value.objAccount.Id} style="padding: 5px;">
                        <tr key={it.value.objAccount.Id}>
                            <td colspan="5">
                                <template if:true={it.value.contactBool}>    
                                    <b key={it.value.objAccount.Id}>Contacts found for this Account are below:</b>
                                        <template iterator:it={it.value.objAccount.Contacts}>
                                            <div style="padding:1px;" key={it.value.Id}>
                                                Name: {it.value.FirstName} {it.value.LastName}<br/>
                                                Email: {it.value.Email}
                                            </div>
                                        </template>
                                </template>
                                <template if:false={it.value.contactBool}>    
                                    <b key={it.value.objAccount.Id}>No Contacts found for this Account!!!</b>
                                </template>
                            </td>
                        </tr>
                    </template>                    
                </template>
            </tbody>
        </table>
    </div>
</template>

JavaScript:

import { LightningElement, wire } from 'lwc';
import fetchAccounts from '@salesforce/apex/AccountController.fetchAccounts';

export default class Sample extends LightningElement {

    records;
    error;

    @wire( fetchAccounts )  
    wiredAccount( { error, data } ) {

        if (data) {

            console.log( 'Fetched Data ' + JSON.stringify( data ) );
            this.records = data;

        } else if ( error ) {

            this.error = error;
            this.records = undefined;

        }

    }  

    hideAndShow( event ) {

        let indx = event.target.dataset.recordId;
        console.log( 'Index is ' + indx );

        if ( this.records ) {

            let recs =  JSON.parse( JSON.stringify( this.records ) );
            let currVal = recs[ indx ].hideBool;
            console.log( 'Current Val ' + currVal );
            recs[ indx ].hideBool = !currVal;
            this.records = recs;
            console.log( 'After Change ' + this.records[ indx ].hideBool );

        }

    }

    expandAll() {

        if ( this.records ) {

            let recs =  JSON.parse( JSON.stringify( this.records ) );

            for ( let rec of recs ) {
                rec.hideBool = false;
            }

            this.records = recs;

        }

    }

    collapseAll() {

        if ( this.records ) {

            let recs =  JSON.parse( JSON.stringify( this.records ) );

            for ( let rec of recs ) {
                rec.hideBool = true;
            }

            this.records = recs;

        }

    }

}

Output:

Leave a Reply