3

I am trying to create a lightning component that gets data from a server and displays them in individual lightning components which are dynamically created. I built a prototype, and I am trying to get it to render the created lightning components correctly. Here is the code for the Javascript client-side controller:

handleComponent : function(component, event, helper) {
    var xmlhttp = new XMLHttpRequest();

    xmlhttp.open('GET', <the url to my service>);
    xmlhttp.onreadystatechange = function(comp)
    {
        component.set("v.loading", false);
        if (xmlhttp.readyState == 4)
        {
            var cont = JSON.parse(xmlhttp.responseText);
            var i;
            for (i = 0; i < cont.items.length; ++i)
            {
                var item = cont.items[i];
                $A.createComponent(
                    "c:itemViewer",
                    {
                        "itemTitle": item.title,
                        "itemImageUrl": item.imageUrl,
                        "itemContent": item.content
                    },
                    function(newInp, status, errorMessage){
                        if (status === "SUCCESS") {
                            var body = component.get("v.body");
                            body.push(newInp);
                            component.set("v.body", body);
                        }
                        else if (status === "INCOMPLETE") {
                            console.log("No response from server or client is offline.")
                        }
                            else if (status === "ERROR") {
                                console.log("Error: " + errorMessage);
                            }
                        }
                    );
            }
        }
    }

    component.set("v.loading", true);
    xmlhttp.send();
}

And the code for the component itself (itemViewer is another custom lightning component, which I built separately to display the items):

<aura:component implements="force:appHostable">
<aura:attribute name="loading" type="boolean" default="false"/>
<lightning:button label="Create Component" onclick="{!c.handleComponent}"/>
{!v.body}
<aura:if isTrue="{!v.loading}">
    <div aura:id="spinnerId" class="slds-spinner_container">
        <div class="slds-spinner--brand  slds-spinner slds-spinner--large slds-is-relative" role="">
            <span class="slds-assistive-text">Loading</span>
            <div class="slds-spinner__dot-a"></div>
            <div class="slds-spinner__dot-b"></div>
        </div>
    </div>
</aura:if>

The problem is that it is very slow to render when I click the "Create Component" button, if I'm lucky. Usually nothing shows up (but it sometimes does). I've also concluded that the problem is not the asynchronous tasks blocking or taking a long time, but rather that the component is getting created, and the page is not updating to show the new components. Is there something I need to be doing to get these custom components created in this manner to render properly?

1

One thing that is missing is the $A.getCallback wrapper:

xmlhttp.onreadystatechange = $A.getCallback(function(comp) {...});

that the documentation explains is needed:

Use $A.getCallback() to wrap any code that modifies a component outside the normal rerendering lifecycle, such as in a setTimeout() call. The $A.getCallback() call ensures that the framework rerenders the modified component and processes any enqueued actions.

and adding that should fix the problem. (As would changing to a normal call to an @AuraEnabled method.)

I also suggest you change to the $A.createComponents method where you make one request but supply an array of component definitions and receive an array of new components in the callback. This locks down the ordering too whatever server requests are involved to load the component definition.

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.