[SalesForce] Static values for ``

I've got a working datatable using the following in my component markup:

<lightning:datatable columns="{!v.columns}" data="{!v.configuration.channels}" keyField="channelId"/>

Columns is a List attribute:

<aura:attribute name="columns" type="List"/>

And is being set via the controller:

component.set("v.columns", [{label: 'Type', fieldName: 'type'}, {label: 'ID', fieldName: 'channelId'}]);

And all is right with the world. Except for the verbosity. As usual with Lightning I find myself needing to write more code than should really be required. I was originally trying to do the columns like this:

<lightning:datatable
    columns="[{label: 'Type', fieldName: 'type'}, {label: 'ID', fieldName: 'channelId'}]"
    data="{!v.configuration.channels}"
    keyField="channelId"/>

But this wasn't working. I know that attribute binding is done at the Java level of the platform, but is there a way to simplify the working setup so that it doens't require extra code in the controller and an extra attribute that's not used for anything else?

Best Answer

Short Answer

No.

Long Answer

I'm not going to spend a ton of time on this, but the general idea is that each component gets to decide how to parse its attributes.

As a working example, this code outputs what you expect:

<aura:iteration items="[{label: 'Type', fieldName: 'type'}, {label: 'ID', fieldName: 'channelId'}]" var="item">
    {!item.label}: {!item.fieldName}<br />
</aura:iteration>

I tried to figure out where the source for this goes off to, but it's buried deep in the Aura framework, and I don't have the inclination to try and find it, since it could take me hours. The point is, the items attribute parses its data into a native JavaScript list object automatically, if necessary. Most "aura" components do this naturally, unless explicitly noted otherwise.

However, lightning:datatable does no such attribute parsing. The important section of code relevant to this question/answer is this setter method:

set columns(value) {
    this._columns = Array.isArray(value) ? value : [];
    this.updateColumns(this._columns);
}

As you can see, it sets a private member variable (_columns) to the incoming value only if its already an array. It does not attempt to convert the value in to an array if it is not already one. So, the inline expression statement literally comes in as a string value, Array.isArray decides that a String is not an Array (because it is not one), and thus _columns ends up being an empty Array.

So, in conclusion... yes, you can use static inline expressions sometimes. Feel free to try it on every attribute you care to test with. Some will work, others will not. If it doesn't, odds are it wasn't meant to. If you enable Lightning Debug Mode, you can dig deeper into the source and find out why, if you're really curious.

Just remember that each component is free to choose how it handles its attributes, so you cannot make any general assumptions about how other components or attributes work. This is an unfortunate limitation of the platform. Most components are designed to work in a consistent manner with others that have similar attributes, but there is no obligation to do so, and some components just don't work right in certain configurations.


If you're willing to put the one-time investment into it, you can take advantage of automatic expression parsing using your own wrapper component. The following code, for example, does render correctly:

<aura:component >
    <aura:attribute name="columns" type="List" />
    <aura:attribute name="data" type="List" />
    <aura:attribute name="keyField" type="String" />

        <lightning:datatable
                         columns="{!v.columns}"
                         data="{!v.data}"
                         keyField="{!v.keyField}"/>
</aura:component>

<c:lightningDataTableWrapper
                     columns="[{label: 'Type', fieldName: 'type'}, {label: 'ID', fieldName: 'channelId'}]"
                     data="{!v.configuration.channels}"
                     keyfield="channelId"/>

Basically, for every attribute you want to support, you'd have to add it to your wrapper component. You'll have to decide if the wrapper class is worth the cost of static attribute support.

Related Topic