Merged cell in custom table displaying in next column instead of next row

htmllightning-web-componentstable

I have a list of records that needs to be grouped by store name and displayed on a table with a collapse/expand function. Table data is displayed properly when expanded, but is displayed as one row when collapsed. How do I prevent the grouped store names from displaying as one row? Any help would be much appreciated. Thank you.

Collapsed Table
enter image description here
Expanded Table
enter image description here

sample.html

<template>
    <table class="slds-table slds-table_cell-buffer slds-table_bordered slds-table_col-bordered slds-table_striped slds-max-medium-table_stacked">
            <thead>
                <tr>
                    <th scope="col">
                        <div class="slds-truncate" title="">Store Name</div>
                    </th>
                    <th scope="col">
                        <div class="slds-truncate" title="">Contact Number</div>
                    </th>
                    <th scope="col">
                        <div class="slds-truncate" title="">Department</div>
                    </th>
                </tr>
            </thead>
            <tbody>
                <template if:true={storeArray}>
                    <template for:each={storeArray} for:item="storeName">
                        <tr key={storeName.Store_Name__c} class="slds-hint-parent">
                            <td data-label="Store Name" rowspan={storeName.rowspan}>
                                {storeName.Store_Name__c} 
                                <lightning-button-icon icon-name="utility:chevrondown" alternative-text="Expand" class="slds-m-left_xx-small" onclick={handleExpand}></lightning-button-icon>
                            </td>
                        </tr>
                        <template if:true={showChildren}>
                            <template for:each={storeName.stores} for:item="store">
                                <tr key={store.assetName}>
                                    <td key={store.Contact_Number__c} data-label="Contact Number">
                                        <lightning-formatted-phone value={store.Contact_Number__c}></lightning-formatted-phone>
                                    </td>
                                    <td key={store.Department__c} data-label="Department">
                                        {store.Department__c}
                                    </td>
                                </tr>
                            </template>
                        </template>
                    </template>
                </template>
            </tbody>
        </table>
</template>

sample.js

import { LightningElement, track } from 'lwc';

export default class sample extends LightningElement {
    @track groupedDataMap = [];
    @track storeArray = [];
    @track showChildren = false;

    @track data = [
    {
        "Store_Name__c": "Store A",
        "Contact_Number__c": "12345678901",
        "Department__c": "Sales"
    },
    {
        "Store_Name__c": "Store A",
        "Contact_Number__c": "12345678902",
        "Department__c": "Marketing"
    },
    {
        "Store_Name__c": "Store B",
        "Contact_Number__c": "12345678903",
        "Department__c": "Sales"
    },
    {
        "Store_Name__c": "Store B",
        "Contact_Number__c": "12345678904",
        "Department__c": "Marketing"
    }
];
    connectedCallback() {
        this.groupedDataMap = new Map();

        this.data.forEach(store => {
            if (this.groupedDataMap.has(store.Store_Name__c)) {
                this.groupedDataMap.get(store.Store_Name__c).stores.push(store);
            } else {
                let newStore = {};
                newStore.Store_Name__c = store.Store_Name__c;
                newStore.stores = [store];
                this.groupedDataMap.set(store.Store_Name__c, newStore);
            }
        });
    
        let itr = this.groupedDataMap.values();
        let result = itr.next();
        while (!result.done) {
            result.value.rowspan = result.value.stores.length + 1;
            this.storeArray.push(result.value);
            result = itr.next();
        }
    }

    handleExpand() {
        this.showChildren = !this.showChildren;
    }
}

Best Answer

I analyzed your code by copying it in webcomponents.dev.

looks like it is happening due to rowspan. you are calculating rowspan in connectedcallback and even if showchildren attribute is false you are applying rowspan which is showing incorrect display.

you should only apply rowspan if showchildren is true.

Webcompownnt.dev url : https://webcomponents.dev/edit/XmZ4s6hNbaCo56adbkGF/src/app.html

open preview in a new tab for desktop view.

code to be modified

current code

<tbody>
                <template if:true={storeArray}>
                    <template for:each={storeArray} for:item="storeName">
                        <tr key={storeName.Store_Name__c} class="slds-hint-parent">
                            <td data-label="Store Name" rowspan={storeName.rowspan}>
                                {storeName.Store_Name__c} 
                                <lightning-button-icon icon-name="utility:chevrondown" alternative-text="Expand" class="slds-m-left_xx-small" onclick={handleExpand}></lightning-button-icon>
                            </td>
                        </tr>
                        <template if:true={showChildren}>
                            <template for:each={storeName.stores} for:item="store">
                                <tr key={store.assetName}>
                                    <td key={store.Contact_Number__c} data-label="Contact Number">
                                        <lightning-formatted-phone value={store.Contact_Number__c}></lightning-formatted-phone>
                                    </td>
                                    <td key={store.Department__c} data-label="Department">
                                        {store.Department__c}
                                    </td>
                                </tr>
                            </template>
                        </template>
                    </template>
                </template>
            </tbody>

modified code:

<tbody>
            <template if:true={storeArray}>
                <template for:each={storeArray} for:item="storeName">
                    <template if:false={showChildren}>
                        <tr key={storeName.Store_Name__c}>
                            <td data-label="Store Name">
                                {storeName.Store_Name__c}
                                <lightning-button-icon icon-name="utility:chevrondown" alternative-text="Expand"
                                    class="slds-m-left_xx-small" onclick={handleExpand}></lightning-button-icon>
                            </td>
                        </tr>
                    </template>
                    <template if:true={showChildren}>
                        <tr key={storeName.Store_Name__c}>
                            <td data-label="Store Name" rowspan={storeName.rowspan}>
                                {storeName.Store_Name__c}
                                <lightning-button-icon icon-name="utility:chevrondown" alternative-text="Expand"
                                    class="slds-m-left_xx-small" onclick={handleExpand}></lightning-button-icon>
                            </td>
                        </tr>
                        <template for:each={storeName.stores} for:item="store">
                            <tr key={store.assetName}>
                                <td key={store.Contact_Number__c} data-label="Contact Number">
                                    <lightning-formatted-phone value={store.Contact_Number__c}></lightning-formatted-phone>
                                </td>
                                <td key={store.Department__c} data-label="Department">
                                    {store.Department__c}
                                </td>
                            </tr>
                        </template>
                    </template>
                </template>
            </template>
        </tbody>
Related Topic