[SalesForce] How to force width resizing of lightning:datatable

I've structured a component in a way that either a lightning:datatable aura component or a lightning:dualistbox. The dual list box is used to set the columns attribute of the data table. The issue is that in this way, even if the values of the data table are correct, their width is not: they are shrunk as much as possible. If I resize the window then the columns width will adjust correctly automatically. There is a way to force the data table columns adjustment or to fake the window resizing event?


In the following a minimal example to make my case clearer.

parent.cmp

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes" access="global">
    <aura:attribute name="data" type="List"/>
    <aura:attribute name="dataTableColumns" type="List"/>
    <lightning:tabset>
        <!-- Table Tab -->
        <lightning:tab label="Table" title="Table">
            <c:datatableChild data="{!v.data}" columns="{!v.dataTableColumns}"/>
        </lightning:tab>

        <!-- Settings Tab -->
        <lightning:tab label="Settings" title="Settings">
            <c:duallistboxChild dataTableColumns="{!v.dataTableColumns}"/>
        </lightning:tab>
    </lightning:tabset>
</aura:component>

datatableChild.cmp

<aura:component >
    <!-- Table Attributes -->
    <aura:attribute name="data" type="Object" access="public" required="true"/>
    <aura:attribute name="columns" type="List" access="public" required="true"/>
    <aura:attribute name="hideCheckBoxColumn" type="Boolean" default="true"/>
    <aura:attribute name="sortedBy" type="String" default="Value1"/>
    <aura:attribute name="sortedDirection" type="String" default="asc"/>
    <aura:attribute name="defaultSortDirection" type="String" default="asc"/>

    <!-- Table -->
    <lightning:datatable
        keyField="Id"
        data="{!v.data}"
        columns="{!v.columns}"
        hideCheckboxColumn="{!v.hideCheckBoxColumn}"
        sortedBy="{!v.sortedBy}"
        sortedDirection="{!v.sortedDirection}"
        defaultSortDirection="{!v.defaultSortDirection}"/>
</aura:component>

duallistboxChild.cmp

<aura:component >
    <!-- Attributes -->
    <aura:attribute 
        name="visibleColumnsOptions" 
        type="List" 
        default="[
            {label: 'Column1', value: 'Value1'},
            {label: 'Column2', value: 'Value2'},
            {label: 'Column3', value: 'Value3'},
            {label: 'Column4', value: 'Value4'},
            {label: 'Column5', value: 'Value5'},
            {label: 'Column6', value: 'Value6'}]" 
        access="public"/>
    <aura:attribute 
        name="visibleColumnsValues" 
        type="List" 
        default="['Value1', 'Value2', 'Value3']"/>
    <aura:attribute 
        name="visibleColumnsRequiredOptions" 
        type="List" 
        default="['Value1']"/>
    <aura:attribute 
        name="dataTableColumns" 
        type="List" 
        access="public"/>

    <!-- Settings -->
    <lightning:dualListbox
        name="visibleColumns"
        label="Select visible columns"
        sourceLabel="Available"
        selectedLabel="Selected"
        options="{!v.visibleColumnsOptions}"
        value="{!v.visibleColumnsValues}"
        onchange="{!c.setDataTableColumns}"/>
</aura:component>

duallistboxChildController.js

({
    setDataTableColumns : function(component, event, helper) {
        const selectedOptions = component.get("v.visibleColumnsValues");
        var columns = [];
        for (let selectedOption of selectedOptions) {
            switch (selectedOption) {
                case 'Value1':
                    columns.push({fieldName: 'Value1', label: 'Column1', sortable: true, type: 'text'});
                    break;
                case 'Value2':
                    columns.push({fieldName: 'Value2', label: 'Column2', sortable: true, type: 'text'});
                    break;
                case 'Value3':
                    columns.push({fieldName: 'Value3', label: 'Column3', sortable: true, type: 'text'});
                    break;
                case 'Value4':
                    columns.push({fieldName: 'Value4', label: 'Column4', sortable: true, type: 'text'});
                    break;
                case 'Value5':
                    columns.push({fieldName: 'Value5', label: 'Column5', sortable: true, type: 'text'});
                    break;
                case 'Value6':
                    columns.push({fieldName: 'Value6', label: 'Column6', sortable: true, type: 'text'});
                    break;
                default:
                    console.error("An unexpected column has been selected. Selected column: " + selectedOption);
                    // Do something, this case should never happen
                    break;
            }
        }
        component.set('v.dataTableColumns', columns);
    }
})

The real page is much more complex. However, for the sake of simplicity in the following there are a couple of screenshot of the situation with the above code.

By simply open the parent and set whatever value of columns in the setting tab this is what happens when the switch back to the table tab:

actual

After taking the step above, resize the window and this is what happens:

expected

What I want is the effect of the second screenshot without having to manually resize the window.

I tried to pass the initial width of the columns inside the columns attribute of lightning:dataTable and it works. I mean that the column width (expressed as pixels) is the same I've provided. However this doesn't solve my troubles since the width is no longer reactive. I tried with percentage values but it broken the column layout.

Best Answer

I was able to solve it. I don't like this solution but I didn't find a better way. Basically, I'm forcing the render of the table when its parent tab is active.

The solution is to embrace the datatableChild component in an aura:renderIf. The helper variable can have any name and it is set to true when the Table tab is active and it set to false when the other tab is active. To achieve this the onactive attribute of lightning:tab can be used.

parent.cmp

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes" access="global">
    <aura:attribute name="data" type="List"/>
    <aura:attribute name="dataTableColumns" type="List"/>
    <aura:attribute name="flag" type="Boolean"/>

    <lightning:tabset>
        <!-- Table Tab -->
        <lightning:tab label="Table" title="Table" onactive="{!c.setFlag}">
            <aura:renderIf isTrue="{!v.flag}">
                <c:datatableChild data="{!v.data}" columns="{!v.dataTableColumns}"/>
            </aura:renderIf>
        </lightning:tab>

        <!-- Settings Tab -->
        <lightning:tab label="Settings" title="Settings" onactive="{!c.unsetFlag}">
            <c:duallistboxChild dataTableColumns="{!v.dataTableColumns}"/>
        </lightning:tab>
    </lightning:tabset>
</aura:component>

parentController.cmp

({
    setFlag : function(component, event, helper) {
        component.set("v.flag", true);
    },

    unsetFlag : function(component, event, helper) {
        component.set("v.flag", false);
    }
})

I discourage the alternative of using aura:if instead of aura:renderIf. It completely reinitialise the component while I'm interested in render only.

As I said, I don't like it very much but it's the best I've achieved so far.

Related Topic