4

Examples of lightning:spinner usage that I've seen are used for delays in controller logic processing, ie waiting on an asynchronous callout. But what I'm trying to solve for is being able to show the spinner while the actual component markup is rendering.

For example, I have a child component that builds a complex table using nested aura:iteration and aura:if tags, and takes 5-10 seconds for the actual table to be rendered on the page, while the controller logic completes instantly.

I can't figure out how to turn on the spinner at the beginning of the render process, then turn it off after.

My attempt

I tried using two standard event handlers for init and render, which I understood to be fired on either end of the rendering process. I paired lightning:spinner with an <aura:if isTrue="{!v.showSpinner}">, then in each of those handler methods I set showSpinner to true and false, respectively.

component:

<aura:attribute name="showSpinner" type="Boolean" default="true"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<aura:handler name="render" value="{!this}" action="{!c.onRender}"/>

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

controller:

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

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

Outcome

Visually: About 5 seconds pass before the page finishes rendering (during which the SF page framework displays, including the parent lightning component, but the table inside the child component does not), then the table appears. The spinner does not show at all.

Console Log: I expected that onRender wouldn't fire till after the table was displaying, but apparently not, because immediately upon component creation and prior to the table displaying, the following console log lines displayed:

doinit fired 
onRender fired  
onRender fired

Then, immediately after the table finished rendering, onRender fired three more times.

So that explains why the spinner doesn't show. The first onRender fires instantly, turning off the spinner.

What I don't get is why onRender is firing five times during the initial rendering of the table, when the data object that populates the table hasn't been manipulated by code or user entry yet.

How can I ensure that the spinner isn't hidden until after the table component truly finishes rendering? is there a an event other than init that flags the start of any individual render process, since there are clearly several rerenderings on the initial page load?

9
  • Something I do often is to show the spinner by default so when the component starts the load the spinner is already displayed. Then I will hide the spinner once I have gotten all the information and stored it into an attribute. You could try doing it a similar way. Is there an attribute or something that you can look at to decide if everything has been loaded? Commented Feb 14, 2019 at 20:15
  • Zack, therein lies my difficulty, because all logic and variables have been loaded prior to the actual rendering of the table, so I'm not sure what I can check against to determine whether the rendering is complete, other than an event that actually fires upon completion.
    – smohyee
    Commented Feb 14, 2019 at 20:17
  • Have you read through this? developer.salesforce.com/docs/atlas.en-us.lightning.meta/… Commented Feb 14, 2019 at 20:22
  • Also maybe look into custom rendered developer.salesforce.com/docs/atlas.en-us.lightning.meta/… Commented Feb 14, 2019 at 20:28
  • Yep, have been through both of those, it's how I learned about the render event! I may need to take a closer look at a custom renderer, but I would expect that the standard rendering engine would have a similar set of events that fire on init, on start of render, on completion of render, etc. I can't find the 'on start of render' equivalent.
    – smohyee
    Commented Feb 14, 2019 at 20:52

2 Answers 2

1

Using a window.setTimeout() worked for me.

helper.displaySpinner();

window.setTimeout($A.getCallback(function(){
    // Your async code here
    helper.hideSpinner();
}), 1);
0

Just figured out a way to get my specific situation to work.

My table component is actually a grandchild of the top level parent component. The middle component is created dynamically using $A.createComponent on the grandparent, and the grandchild is inserted statically into the middle component using <c:grandchild_Component>

Instead of trying to control and display the spinner on the middle or grandchild components, I moved it up to the parent component. showSpinner is set to true by default, and the attribute is set to false within the callback function of the $A.createComponent that creates the middle component, like such:

$A.createComponent("c:middle_component", {
                                "aura:id": "step3",
                                },
                                function (childcmp, status, errorMessage) {
                                    if (status === "SUCCESS") {
                                        component.set("v.content", childcmp);
                                        component.set("v.currentStep", 'step3');
                                        console.log('spinner turned off');
                                        component.set("v.showSpinner", false);
                                    } else if (status === "INCOMPLETE") {
                                        console.log("No response from server or client is offline.");
                                    } else if (status === "ERROR") {
                                        console.log("Error: " + errorMessage);
                                    }
                                }
                            );

One peculiarity I've noted in doing this is that the grandchild's init and render methods don't fire until after the callback from it's parent component is completed. I would have thought that $A.createComponent wouldn't be considered complete until all children components of the created components were also created and rendered.

You must log in to answer this question.

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