Good afternoon everyone,
I have a question regarding the use of the $A.createComponents()
Lightning function. This may be somewhat complex so I will try to make it as clear as possible for everyone's benefit, including my own.
1.) At the Application level, I currently have the following function in my client-side controller:
doInit: function(cmp, event, helper) {
//Dynamically Add component to application body on application load
$A.createComponents([["c:SelfServiceTimeOffRequestAction",{attribute:true}]],
function(newCmp, status){
if (cmp.isValid() && status === 'SUCCESS') {
cmp.set("v.body", newCmp);
}
});
},
The purpose for this function is to dynamically insert a specified component into the body of the application when the application loads. Currently, it is loading the"SelfServiceTimeOffRequestAction" component when the application loads.
2.) I have a second function in my application client-side controller that performs the same function except as an event handler for a custom Lightning event that fires based on button clicks or anchor links in other child components to provide navigation functionality between components in the application.
handleAddComponent : function(cmp, event, helper){
var cmpId = event.getParam("cmpId");
if(cmpId !== null && cmpId !== ''){
var cmpFinal = "c:" + cmpId;
$A.createComponents([[cmpFinal,{attribute:true}],],
function(newCmp, status){
if (cmp.isValid() && status === 'SUCCESS') {
cmp.set("v.body", newCmp);
}
});
}
In the application markup, I have declared all components as dependencies so that any component can be passed to either of these functions and a new call to the component server will not be required each time. See this post for more information.
<aura:application implements="force:appHostable">
<!-- Attributes -->
<aura:dependency resource="markup://c:*" type="COMPONENT"/>
<!-- Registered Application Events -->
<aura:registerEvent name="HideArticleDescription" type="c:HideArticleDescription"/>
<!-- Event Handlers -->
<aura:handler value="{!this}" name="init" action="{!c.doInit}"/>
<aura:handler event="c:AddComponent" action="{!c.handleAddComponent}"/>
<!-- Application Body -->
<div class="container-fluid">
<!-- New Case Modal -->
<c:SelfServiceNewCaseModal />
<div class="row">
<!-- Header -->
<c:SelfServiceHeader />
</div>
<div class="row">
<div class="col-md-12">
<div class="row">
<!-- Main Body -->
**{!v.body}**
</div>
<div class="row">
<c:Footer />
</div>
</div>
</div>
</div>
<!--*******************************-->
<!-- Script Files -->
<ltng:require scripts="/resource/CommunityResources/js/jquery.min.js, /resource/CommunityResources/js/bootstrap.min.js" afterScriptsLoaded="{!c.OnScriptsLoaded}"/>
</aura:application>
I have highlighted the area where I am dynamically adding the application body using {!v.body}.
3.) My issue lies in this next step. Within the one of the child components contained within the SelfServiceTimeOffRequestAction component that is loading when the application initializes, I am calling the $A.createComponents()
function again to dynamically add a child component to the SelfServiceTimeOffRequestAction component based on some criteria.
This is the markup reference in the SelfServiceTimeOffRequestAction to the first child:
<div class="col-md-6">
<c:SelfServiceTimeOffActionForm />
</div>
Within the SelfServiceTimeOffActionForm component is there the $A.createComponent()
function is used a second time.
This is the full function in the helper of the SelfServiceTimeOffActionForm component:
getSelfServiceSettingSteps : function(cmp){
//Call the listTimeOffRequests Apex class method
var action = cmp.get("c.getSelfServiceSettings");
var self = this;
action.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
var result = response.getReturnValue();
cmp.set("v.noOfSteps", result.No_of_Steps__c);
var noOfSteps = cmp.get("v.noOfSteps");
if(!$A.util.isEmpty(noOfSteps)){
console.log('Steps Not empty');
var firstStep = (noOfSteps) - (noOfSteps - 1);
if(firstStep === 1){
**$A.createComponents([["c:SelfServiceActionFormStep1",{attribute:true}]],
function(newCmp, status){
if (cmp.isValid() && status === 'SUCCESS') {
console.log('Create Cmp Success');
cmp.set("v.body", newCmp);**
}
});
}
}
}
});
$A.enqueueAction(action);
},
What I am seeing is that the SelfServiceTimeOffRequestAction component will render before the SelfServiceTimeOffActionForm component finishes rendering, which presents a blank area of the containing component. I was thinking that declaring all components as a dependency at the application level would prevent the application from rendering until all components had completed rendering an retrieving their data. Ideally, I would like for the application to not render to the page until all the components are visible.
I have provided a link to a video recording to show and clarify what I am seeing on the page: Click HERE for the video.
Does anyone have some suggestions regarding how I could resolve this?
Thanks!