1

I recently asked a related question about how to display the lightning:spinner while waiting for a component to render. Although I found a way to make it work, and have thoroughly reviewed the 'Events fired during rendering lifecycle' and related articles, I'm still unclear on how to solve for this new problem:

Example:

lightning:tabset uses lazy load, and will wait to create components inside a tab until you click it.

My tabs hold a child component that displays a fairly complex spreadsheet-like table, built with a set of nested aura:iterations and aura:if components. The table component takes around 5 seconds to finish rendering and display on the screen, and although I'm not positive, the testing I've done suggests the delay is due to the rendering time needed for those iterations/ifs in the component markup.

My goal:

For the spinner to display when the user first clicks on a new tab, and to hide by the time the tab is fully rendered.

Relevant code:

Parent component markup:

<aura:attribute name="showSpinner" type="Boolean"/>

<aura:if isTrue="{!v.showSpinner}">
    <lightning:spinner variant="brand" alternativeText="Page loading..." aura:id="loadingSpinner"/>
</aura:if>

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

<lightning:tabset variant="scoped" onselect="{!c.onchangeTab}">                    
    <lightning:tab label="Tab 1">               
        <c:table_cmp rowObjects="{!v.rowObjects}"/>        
    </lightning:tab>
    <lightning:tab label="Tab 2">               
        <c:table_cmp rowObjects="{!v.rowObjects}"/>        
    </lightning:tab>
</lightning:tabset>

Parent controller:

onchangeTab : function(component, event, helper){
    console.log('onchangetab fired');
    component.set("v.showSpinner", true);
    helper.selectTable(component, helper);       
},

onRender : function(component, event, helper){
    console.log('elimination onRender fired');
    component.set("v.showSpinner", false);
},

My problem:

The spinner doesn't actually display until after the tab is changed and the table is fully rendered, at which time the onRender method has already turned it back off. So the spinner never displays!

If I throw a console.log() line in the beginning of my onselect method, right before my component.set("v.showSpinner", true) line, it shows that the method fires immediately upon clicking the tab, prior to the tab changing + rendering.

My guessplanation for this behavior is that even though the logic fires immediately, the rendering of the spinner finishes at the same time as the rest of the tab, at which point onRender turns it back off.

So how can I control the order of rendering, so that the spinner renders/displays prior to the rest of the tab rendering?

1

Give the DOM a moment to process the remaining change events by inserting a small wait:

setTimeout($A.getCallback(helper.selectTable.bind(helper, component, helper)), 0);

$A.getCallback ensures that you have a new Aura life cycle (important to get rendering done correctly), Function.prototype.bind makes a function reference so the function is not called immediately, but rather when the timeout expires, and 0ms (the last parameter) means "as soon as possible."

This brief asynchronous delay ensures that the spinner is given a chance to display before the heavy processing begins.

4
  • Thanks Fox, but I ran into a problem with this solution: unlike previously, when onRender only fired after the tab change + table render, now onRender is firing (twice?) immediately after onChangeTab fires, prior to the tab + table rendering. Then` onRender` fires again after the table displays. The immediate onRender is turning the spinner off before it displays.
    – smohyee
    Feb 15 '19 at 17:03
  • Oh well you know what fixed it? Moving the component.set("v.showSpinner", false); from the onRender method to the end of the selectTable method. I wouldn't have expected that, because all that method does is update the array attribute used by the aura:iteration tags to build the table. Does this mean that I was wrong in assuming the delay was caused by the markup rendering, and the delay is actually caused by the logic in that method?
    – smohyee
    Feb 15 '19 at 17:11
  • @smohyee most likely. You would need to have thousands of rows before the rendering time would be in the "seconds" territory. You might need to do some optimization elsewhere.
    – sfdcfox
    Feb 15 '19 at 18:05
  • hmm ok, I'll have to learn how to measure processing time for pieces of JS code beyond sticking console.log lines in everywhere, haha. Thanks Fox!
    – smohyee
    Feb 15 '19 at 20:53

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.