7

I’ve got a lightning component that creates itself recursively and asynchronously in order to fully render a tree-structure data. Here’s a sample code that simplifies the problem.

TestApp.app

<aura:application>
    <ul>
        <c:node level="3"/>
    </ul>
</aura:application> 

Node.cmp

<aura:component>
    <aura:attribute name="level" type="Integer" />
    <aura:attribute name="children" type="List" access="private" />
    <aura:handler name="init" value="{!this}" action="{!c.createChildren}"/>

    <li>
        Level {!v.level}
        <ul>
            <aura:iteration items="{!v.children}" var="child">
                <c:node level="{!v.level - 1}" />
            </aura:iteration>
        </ul>
    </li>
</aura:component>

NodeController.js

({
    createChildren : function(component, event, helper) {
        var level = component.get('v.level'),
            children = [];

        for (var i = 0; i < level; i++) {
            children.push({});
        }

        component.set("v.children", children);
    }
})

DEMO

enter image description here

QUESTION

How can the app know when the the full tree has been rendered?

In my use case, the controller.js is a server call so it's possible some nodes could finish sooner having no children, while some can continue expanding.

2 Answers 2

6

Have node include an event that says when it is done. It is considered done when all of its children are considered done. If it has nothing to expand, it is done at the end of the server call. Otherwise, each time a child says it's done, check to see if there are any pending. Something like this:

<aura:component>
    <aura:attribute name="level" type="Integer" />
    <aura:attribute name="children" type="List" access="private" />
    <aura:attribute name="counter" type="Integer" default="0" />
    <aura:handler name="init" value="{!this}" action="{!c.createChildren}"/>
    <aura:registerEvent name="done" type="c:genericEvent" />

    <li>
        Level {!v.level}
        <ul>
            <aura:iteration items="{!v.children}" var="child">
                <c:node level="{!v.level - 1}" done="{!c.check}" />
            </aura:iteration>
        </ul>
    </li>
</aura:component>

({
    createChildren : function(component, event, helper) {
        var level = component.get('v.level'),
            children = [];

        for (var i = 0; i < level; i++) {
            children.push({});
        }

        component.set("v.children", children);
        if(!children.length) {
          component.getEvent("done").fire();
        }
    },
    check: function(component, event, helper) {
        component.set("v.counter", 1 + component.get("v.counter"));
        if(component.get("v.counter") === component.get("v.children").length) {
            component.getEvent("done").fire();
        }
    }
})

The application just listens for that event, too:

<aura:application>
    <ul>
        <c:node level="3" done="{!c.nodesLoaded}" />
    </ul>
</aura:application> 

N.B. I didn't actually test this, but it should be simple enough to spot any obvious mistakes, I think.

3
  • Wow. I've been on this all day!
    – Jan Julian
    Commented Jan 18, 2019 at 2:25
  • @jmrjulian is it working? Because events will got fired before parent components are rendered. Commented Jan 18, 2019 at 11:10
  • @ManjotSingh Yes, each child notifies its immediate parent when it is done rendering, then that node itself notifies its parent when it is done rendering, and so on up the tree. The top-level parent is the last component to get notified, indicating that all data has been loaded recursively.
    – sfdcfox
    Commented Jan 18, 2019 at 11:25
1

Your situation is tricky but if you know how many component will be created then you can tell the tree is fully loaded. You need to have a variable at root level which will tell you the total component count.

Each child component should speak with their parent after it is loaded, assuming parent node is loading and then child node is loading. Use below out of the box event along with custom event to communicate with parent.

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

Any reason lightning tree cannot be used. If the JSON is not that big you can keep appending it.

You must log in to answer this question.

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