Recursive lightning component - how to know when it's fully rendered?












3















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.










share|improve this question



























    3















    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.










    share|improve this question

























      3












      3








      3








      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.










      share|improve this question














      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.







      lightning-aura-components






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked 2 hours ago









      jmrjulianjmrjulian

      1,3861322




      1,3861322






















          2 Answers
          2






          active

          oldest

          votes


















          1














          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.






          share|improve this answer
























          • Wow. I've been on this all day!

            – jmrjulian
            30 mins ago



















          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.






          share|improve this answer























            Your Answer








            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "459"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsalesforce.stackexchange.com%2fquestions%2f247064%2frecursive-lightning-component-how-to-know-when-its-fully-rendered%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            1














            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.






            share|improve this answer
























            • Wow. I've been on this all day!

              – jmrjulian
              30 mins ago
















            1














            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.






            share|improve this answer
























            • Wow. I've been on this all day!

              – jmrjulian
              30 mins ago














            1












            1








            1







            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.






            share|improve this answer













            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.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 1 hour ago









            sfdcfoxsfdcfox

            250k11193431




            250k11193431













            • Wow. I've been on this all day!

              – jmrjulian
              30 mins ago



















            • Wow. I've been on this all day!

              – jmrjulian
              30 mins ago

















            Wow. I've been on this all day!

            – jmrjulian
            30 mins ago





            Wow. I've been on this all day!

            – jmrjulian
            30 mins ago













            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.






            share|improve this answer




























              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.






              share|improve this answer


























                1












                1








                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.






                share|improve this answer













                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.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 1 hour ago









                Avijit ChakrabortyAvijit Chakraborty

                1,2151515




                1,2151515






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Salesforce Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsalesforce.stackexchange.com%2fquestions%2f247064%2frecursive-lightning-component-how-to-know-when-its-fully-rendered%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Polycentropodidae

                    Magento 2 Error message: Invalid state change requested

                    Paulmy