[SalesForce] Lightning component: Child rows in data table

I have a data table based on Lightning component. In one of the column it displays Icon and when user click it should expand and show more information as child row. Is it possible to achieve this without using JQuery?

<table aura:id="companyList" class="slds-table slds-table--bordered slds-table_cell-buffer slds-max-medium-table--stacked-horizontal slds-hide" role="listbox">
    <thead>
    <tr >
        <th colspan="4" scope="col">
            <aura:if isTrue="{!v.searching}">
                <div role="status" class="slds-spinner slds-spinner_large slds-spinner_brand ">
                    <span class="slds-assistive-text">Searching for Companies</span>
                    <div class="slds-spinner__dot-a"></div>
                    <div class="slds-spinner__dot-b"></div>
                </div>
            </aura:if>
            <div class="slds-grid">
                <div class="slds-col slds-align-bottom">
                    <p class="slds-text-body--small page-header__info">{!v.SECompanies.length} Record(s)</p>
                </div>
            </div>
        </th>
    </tr>
    <tr class="slds-text-heading--label">
        <th scope="row" class="nobordertop">Action</th>
        <th scope="col" class="nobordertop">Protection Info</th>
        <th scope="col" class="nobordertop">Company ID</th>
        <th scope="col" class="nobordertop">Company</th>
        <th scope="col" class="nobordertop">Ultimate Parent Co</th>
        <th scope="col" class="nobordertop">Street</th>
        <th scope="col" class="nobordertop">Address</th>
    </tr>
    </thead>
    <tbody>
    <aura:iteration items="{!v.SECompanies}" var="company" indexVar="rowIndex">
        <tr data-data="{!rowIndex}">
            <td data-data="{!rowIndex}">
                <lightning:buttonMenu onselect="{!c.handleSelect}" alternativeText="Toggle menu">
                    <lightning:menuItem label="Edit" value="menuitem1" iconName="action:edit" />
                    <lightning:menuItem label="New Opportunity" value="menuitem2" iconName="action:new_opportunity" />
                </lightning:buttonMenu>
            </td>
            <td data-index="{!rowIndex}" data-label="Protection Info" title="Protection Info">
                <button class="slds-button slds-button--icon-border-filled slds-button--icon-border-small" onclick="{!c.handleIconClick}">
                    <lightning:icon class="icon" iconName="{!company.protectionImageSource}" variant="warning" size="small" title="Click to view protection information"/>
                </button>
            </td>
            <td data-label="Company ID" title="Company ID">
                <div><a data-record="{!company.companyId}" >{!company.companyId}</a></div>
            </td>
            <td data-label="Company Name" title="Company Name">
                <button class="slds-button slds-button-neutral" onclick="{!c.companySelected}" data="{!company}" role="option">{!company.companyName}</button>
            </td>
            <td data-label="Ultimate Parent Name" title="Ultimate Parent Name">
                <div><a data-record="{!company.ultimateParentName}" >{!company.ultimateParentName}</a></div>
            </td>
            <td data-label="Street" title="Street">
                <div><a data-record="{!company.street1}" >{!company.street1}</a></div>
            </td>
            <td data-label="Address" title="Address">
                <div><a data-record="{!company.address}" >{!company.address}</a></div>
            </td>
        </tr>
    </aura:iteration>
    </tbody>
</table>



({
doInit : function(component, event, helper) {
    component.set("v.rows", [
        { Name: "Action",
          expanded: false
        },
        { Name: "Protection Info",
          expanded: false,
        children: [
        { Name: "Protection Desc" }
        ]},
        { Name: "Company ID",
          expanded: false
        },
        { Name: "Company",
          expanded: false
        },
        {
          Name: "Ultimate Parent Co",
          expanded: false
        },
        {
          Name: "Street",
          expanded: false
        },
        {
          Name: "Address",
          expanded: false
        }
    ]);     
}

});

handleIconClick: function(component, event) {
var rows = component.get("v.rows");
rows[event.target.dataset.index].expanded = !rows[event.target.dataset.index].expanded;
component.set("v.rows", rows);
}

enter image description here

Best Answer

Is it possible to achieve this without using JQuery?

Yes. If you can do something with JQuery, you can do it without JQuery. It's all JavaScript. As an addendum, anything you can do in JQuery you can do without JQuery and get better performance.

In the interest of keeping things brief, I'm not going to write out a full copy of your code with modifications, but a smaller, more generalized example that demonstrates how to do what you're trying to do.


<aura:application >
    <aura:attribute name="rows" type="Object[]" />
    <aura:handler name="init" value="{!this}" action="{!c.init}" />

    <table>
        <tbody>
            <aura:iteration items="{!v.rows}" var="row" indexVar="rowIndex">
                <tr>
                    <td data-index="{!rowIndex}" onclick="{!c.toggle}">
                        {!row.Name}
                    </td>
                </tr>
                <aura:if isTrue="{!row.expanded}">
                    <aura:iteration items="{!row.children}" var="child">
                        <tr>
                            {!child.Name}
                        </tr>
                    </aura:iteration>
                </aura:if>
            </aura:iteration>
        </tbody>
    </table>
</aura:application>

({
    init: function(cmp, evt) {
        cmp.set("v.rows", [
            {Name: "A",
            expanded: false,
            children: [
            { Name: "A1" },
            { Name: "A2" }
            ]},
            {Name: "B",
            expanded: false,
            children: [
            { Name: "B1" },
            { Name: "B2" }
            ]},
            {Name: "C",
            expanded: false,
            children: [
            { Name: "C1" },
            { Name: "C2" }
            ]}
                ]);
    },
    toggle: function(cmp, evt) {
        var rows = cmp.get("v.rows");
        rows[evt.target.dataset.index].expanded = !rows[evt.target.dataset.index].expanded;
        cmp.set("v.rows", rows);
    }
})

As you can see from this code, it's a trivial matter to simply render the extra rows when the "expanded" attribute has been toggled. You should be able to modify this example to suit your needs.

I've purposefully left out all styling and fluff to get to the heart of the matter, which I think this app demonstrates easily. Most likely, you'll just need to add an "expanded" attribute to your data's information, and then toggle it as appropriate.

There's lots of other things you could do with this as well, such as querying the database, making a callout, or whatever else it is you want/need to do to get the data.

Related Topic