Dynamically Creating Components
Client-Side Versus Server-Side Component Creation
The $A.createComponent() and $A.createComponents() methods support both client-side (synchronous) and server-side (asynchronous) component creation. For performance and other reasons, client-side creation is preferred.
To use $A.createComponent(), we need the component definition. If we don’t have the definition already on the client, the framework makes a server trip to get it. You can avoid this server trip by adding an <aura:dependency> tag for the component you’re creating in the markup of the component that calls $A.createComponent(). The tag ensures that the component definition is always available on the client. The tradeoff is that the definition is always downloaded instead of only when it’s needed. This performance tradeoff decision depends on your use case.
A single call to createComponent() or createComponents() can result in many components being created. The call creates the requested component and all its child components. In addition to performance considerations, server-side component creation has a limit of 10,000 components that can be created in a single request. If you hit this limit, explicitly declare component dependencies with the <aura:dependency> tag or otherwise pre-load dependent elements. The components are then created on the client side instead.
There’s no limit on component creation on the client side.
Syntax
The syntax is:
$A.createComponent(String type, Object attributes, function callback)
- type—The type of component to create; for example, "lightning:button".
- attributes—A map of attributes for the component, including the local Id (aura:id).
-
callback(cmp, status,
errorMessage)—The callback to invoke after the component is
created.
The callback has three parameters.
- cmp—The component that was created. This parameter enables you to do something with the new component, such as add it to the body of the component that creates it. If there’s an error, cmp is null.
- status—The status of the call. The possible values are SUCCESS, INCOMPLETE, or ERROR. Always check that the status is SUCCESS before you try to use the component.
- errorMessage—The error message if the status is ERROR.
Example
Let’s add a dynamically created button to this sample component.
<!--c:createComponent-->
<aura:component>
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<p>Dynamically created button</p>
{!v.body}
</aura:component>
The client-side controller calls $A.createComponent() to create a lightning:button with a local ID (aura:id) and a handler for the onclick attribute. The function(newButton, ...) callback appends the button to the body of c:createComponent. The newButton that’s dynamically created by $A.createComponent() is passed as the first argument to the callback.
/*createComponentController.js*/
({
doInit : function(cmp) {
$A.createComponent(
"lightning:button",
{
"aura:id": "findableAuraId",
"label": "Press Me",
"onclick": cmp.getReference("c.handlePress")
},
function(newButton, status, errorMessage){
//Add the new button to the body array
if (status === "SUCCESS") {
var body = cmp.get("v.body");
body.push(newButton);
cmp.set("v.body", body);
}
else if (status === "INCOMPLETE") {
console.log("No response from server or client is offline.")
// Show offline error
}
else if (status === "ERROR") {
console.log("Error: " + errorMessage);
// Show error message
}
}
);
},
handlePress : function(cmp) {
// Find the button by the aura:id value
console.log("button: " + cmp.find("findableAuraId"));
console.log("button pressed");
}
})
Creating Nested Components
To dynamically create a component in the body of another component, use $A.createComponents() to create the components. In the function callback, nest the components by setting the inner component in the body of the outer component. This example creates a lightning:icon component in the body of a lightning:card component.
$A.createComponents([
["lightning:card",{
"title" : "Dynamic Components"
}],
["lightning:icon",{
"iconName" : "utility:success",
"alternativeText": "Icon that represents a successful step",
"variant": "success",
"class": "slds-m-around_small"
}]
],
function(components, status, errorMessages){
if (status === "SUCCESS") {
var card = components[0];
var icon = components[1];
// set lightning:icon as the body of lightning:card
card.set("v.body", icon);
cmp.set("v.body", card);
}
else if (status === "INCOMPLETE") {
console.log("No response from server or client is offline.")
// Show offline error
}
else if (status === "ERROR") {
console.log("Error message: " + errorMessages[0].message);
}
}
);
Destroying Dynamically Created Components
After a component that is declared in markup is no longer in use, the framework automatically destroys it and frees up its memory.
If you create a component dynamically in JavaScript and don’t add it to a facet like v.body or another attribute of type Aura.Component[], you have to destroy it manually. Use Component.destroy() to destroy the component and free up its memory to avoid memory leaks.