9

I am trying to dynamically create a data table with two arrays (SObject array and a String array which has field API name).

The two arrays are Contact[] and String[], where String[] consists of ["Id", "Name"].

What I've tried dot notation and square bracket notation but neither worked.

<!-- row -->
<aura:iteration item="{!v.contacts} var="contact">
    <!-- column -->
    <aura:iteration item="{!v.fieldNames} var="fieldName">
        {!contact.fieldName} 
        {!contact[fieldName]}
    </aura:iteration>
</aura:iteration>

Not quite sure what is the correct approach to do this.

  • Jastin. you may need to create one more component. That will take object and field API and place this second component inside aura:iteration.. Basically in this second component use JAVSCRIPT to get the value from object like ex. obj[fieldapi] – Ratan Paul Jan 8 '16 at 5:30
14

As far as I can tell, Lightning components don't support that dynamic reference syntax.


You could consider dynamically generating the content of this component with the component controller:

Component

<aura:component controller="GetAFewContacts">
    <aura:attribute name="contacts" type="Contact[]" />
    <aura:attribute name="fieldNames" type="String[]" default='["Id","Name"]'/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    {!v.body}
</aura:component>

Client-side Controller

({
    doInit : function(component, event, helper) {
        var action = component.get("c.getContacts");
        action.setCallback(this,function(response){
                if (response.getState() === "SUCCESS"){
                    console.log(response.getReturnValue());
                    component.set("{!v.contacts}",response.getReturnValue());

                    var contacts = component.get("{!v.contacts}");
                    var fieldNames = component.get("{!v.fieldNames}");
                    var NewBody = "";
                    for (var i=0; i<contacts.length; i++){
                        for (var ii=0; ii<fieldNames.length; ii++){
                            NewBody += contacts[i][fieldNames[ii]];
                        }
                        NewBody += "\n";
                    }
                    console.log(NewBody);
                    $A.createComponent(
                        "ui:outputText",
                        {
                            "value" : NewBody
                        },
                        function(newComponent){
                            component.set("v.body",newComponent);
                        }
                    )
                }
            }
        );
        $A.enqueueAction(action);
    }
})

Server-side Controller

public class GetAFewContacts {

    @AuraEnabled
    public static list<Contact> getContacts(){
        return [SELECT Id, Name FROM Contact LIMIT 10];
    }

}

Or you could use a second component that sets the value through the component's renderer:

Component

<aura:component controller="GetAFewContacts">
    <aura:attribute name="contacts" type="Contact[]" />
    <aura:attribute name="fieldNames" type="String[]" default='["Id","Name"]'/>

    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />

    <aura:iteration items="{!v.contacts}" var="contact" >
        <aura:iteration items="{!v.fieldNames}" var="fieldName">

            <analysis:ContactAndFieldName contact="{!contact}" fieldName="{!fieldName}" />

        </aura:iteration>
    </aura:iteration>

</aura:component>

Client-side Controller

({
    doInit : function(component, event, helper) {
        var action = component.get("c.getContacts");
        action.setCallback(this,function(response){
                if (response.getState() === "SUCCESS"){
                    component.set("{!v.contacts}",response.getReturnValue());
                }
            }
        );
        $A.enqueueAction(action);
    }
})

Server-side Controller

public class GetAFewContacts {

    @AuraEnabled
    public static list<Contact> getContacts(){
        return [SELECT Id, Name FROM Contact LIMIT 10];
    }

}

Component -- ContactAndFieldName

<aura:component >
    <aura:attribute name="contact" type="Contact" />
    <aura:attribute name="fieldName" type="String" />

    <ui:outputText aura:Id="outputTextId" />

</aura:component>

ContactAndFieldNameRenderer

({

    render : function(component, helper) {
        var ret = this.superRender();

        var Contact = component.get('v.contact');
        var FieldName = component.get('v.fieldName');
        var outputText = component.find("outputTextId");
        outputText.set("v.value",Contact[FieldName]);

        return ret;
    },

})

If an init event is used instead of putting the javascript in the renderer:

Component -- ContactAndFieldName

<aura:component >
    <aura:attribute name="contact" type="Contact" />
    <aura:attribute name="fieldName" type="String" />
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

    <ui:outputText aura:Id="outputTextId" />

</aura:component>

ContactAndFieldNameController

({
    doInit : function(component, helper) {
        var Contact = component.get('v.contact');
        var FieldName = component.get('v.fieldName');
        var outputText = component.find("outputTextId");
        outputText.set("v.value",Contact[FieldName]);
    }
})

(no custom renderer, and everything else is the same)

  • Shouldn't this be done in the renderer? – pchittum Jan 8 '16 at 11:44
  • 1
    After revisiting this question, using a second component and putting the javascript logic in that component's renderer does seem like the better approach. Thanks @Peter and @ Ratan for your comments. – martin Jan 8 '16 at 13:12
  • 2
    @martin why the code that set the ui:outputText needs to be in render instead of init event? won't it work in init? – Praveen Jan 9 '16 at 7:53
  • 1
    @vppravi93 good question. It certainly works if you set an event handler on the init event, and since the init event happens before rendering begins, it might actually be better to put it there. – martin Jan 9 '16 at 9:36
  • 1
    This is working for me; however I am running into issues when I try to reference any cross-object relationship fields. Have any of you ever run into this issue? I can get the field's value when I hard-code it - e.g. contact.product__r.Name, but it doesn't seem to work using the above methodology - Contact[FieldName] @martin – Cole Swain Aug 17 '17 at 21:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.