0

Scenario

In Visualforce we had strong patterns for implementing the rendering of hierarchical structures. As a simplified example (standing for many other use cases) let's say we want to show all Account with their Contacts as a tree-like output.

In Visualforce it is so super easy:

public class elfAccountContacts {
    public Account[] accounts { get; set; }
    public PageReference init() {
        this.accounts = [select Id, Name, (select Id, LastName from Contacts) from Account];
        return null;
    }
}

<apex:page controller="elfAccountContacts" action="{!init}">
    <apex:repeat var="account" value="{!accounts}">
        <div>{!account.Name}<ul>
            <apex:repeat var="contact" value="{!account.contacts}">
                <li>{!contact.LastName}</li>
            </apex:repeat>
        </ul></div>
    </apex:repeat>
</apex:page>

Bam! It looks like this

enter image description here

Now I thought: what the heck, in Lightning it should be easy, too. So I did this:

public class elfAccountContacts {
    @AuraEnabled public static Account[] loadAccounts() {
        return [ select Id, Name, (select Id, LastName from Contacts) from Account];
    }
}

<aura:component controller="elfAccountContacts" implements="flexipage:availableForAllPageTypes,force:hasRecordId" access="global" >
    <aura:attribute name="accounts" type="Account[]" default="" />
    <ltng:require afterScriptsLoaded="{!c.afterScriptsLoaded}" scripts=""/>
    <aura:iteration items="{! v.accounts }" var="account">
        <div>{!account.Name}<ul>
            <aura:iteration items="{! v.account.Contacts }" var="contact">
                <li>{!contact.Name}</li>
            </aura:iteration>
        </ul></div>
    </aura:iteration>
</aura:component>

afterScriptsLoaded : function(cmp, evt, hlp) {
    action = cmp.get("c.loadAccounts");
    action.setCallback( null, function(callbackResult) {
        if(callbackResult.getState()=='SUCCESS') {
            console.log('vanilla', callbackResult.getReturnValue()  );
            cmp.set("v.accounts",callbackResult.getReturnValue() );
        }
    });
    $A.enqueueAction( action );
},

As an unfortunate, using much more code brings only less results. I get the top-level accounts, I get the contacts console logged (so I'm 100% sure that they are there) but I get rendered only the accounts:

enter image description here

Why the contacts are not rendered? What am I doing so wrong here?

7
  • You are querying LastNamebut presenting Name. But Jason's answer looks like the fundamental cause. Personally hate this v. thing.
    – Keith C
    Sep 1, 2017 at 18:30
  • @KeithC LastName for Contact and Name for Account
    – Uwe Heim
    Sep 1, 2017 at 18:33
  • {!contact.Name} in the component markup though.
    – Keith C
    Sep 1, 2017 at 18:34
  • @KeithC you and Jason where right! Now it works. +1 for HATE on that "v."-thing. This was the most error-prone idea someone came up with...
    – Uwe Heim
    Sep 1, 2017 at 18:36
  • You have more lightning mistakes in here, by the way :p
    – sfdcfox
    Sep 1, 2017 at 18:38

1 Answer 1

6

in your second iteration, use {!account.Contacts} instead of {!v.account.Contacts}

<aura:iteration items="{!account.Contacts}" var="contact">
1
  • Great! Thanks, it works now! But it's so painful writing code like this...
    – Uwe Heim
    Sep 1, 2017 at 18:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .