How to store a dynamically created component in attribute of parent component using Aura.component[]?

Scenario:

Re-use of dynamically created components by storing them in Aura.component[] attribute in parent component.

Use-case

I am creating dynamic components in a parent component, and am setting it in body of parent component. Along with this, I want them to be stored in attribute of parent component :

<aura:attribute name="compArray" type="Aura.Component[]"/>

So, after pushing the component in body, I am also pushing the newly dynamically created component to “compArray” as well. Now, this dynamic creation of components occur on change action of a dropdown. The current body is cleared using

component.set("v.body", []);

and new component is pushed in body and “compArray”.

Problem:

On accessing “compArray” it is showing all old components as invalid while only the latest one as valid. If I do not clear the body as done above, it shows all components in “compArray” valid.

Question:

1.Why does clearing of “body” makes elements of Aura.Component[] invalid as they are 2 separate arrays I believe?
2. How to avoid making the components invalid?

Parent component markup:

<aura:attribute name="compArray" type="Aura.Component[]"/>
.
.//some markuphere
.
.
{!v.body}

Parent component helper:

handleChange : function(component){
    var settingType=component.find("settingType").get("v.value");
    var compArr=component.get('v.compArray');
    if(compArr.length > 0){
        for(var i=0;i<compArr.length;i++){
            if(!(compArr[i].isValid())){
                console.log('component is invalid ' , compArr[i]);  //Still Outputs an object
                console.log('component is invalid ' , compArr[i].get("v.settingType"));

                //Outputs error on UI: This page has an error. 
                //You might just need to refresh it.
                //Invalid component tried calling function [get] with arguments           
                //[v.settingType], markup://c:ConfigSettingDetailsComponent [305:0] 
                //Failing descriptor: {InvalidComponent markup://c:ConfigSettingDetailsComponent {305:0}}

            }
            else{
            console.log('component is valid ');  
            }
        }
    }
    else{
        var body = component.get("v.body");
        component.set("v.body", []);
        if(settingType === '----Select----'){
            //don't show spinner or make server call
        }
        else{
            $A.createComponent(
                "c:SampleComponent",
                {
                    "settingType": settingType,
                },
                function(newComponent, status, errorMessage){
                    //Add the new button to the body array
                    if (status === "SUCCESS") {
                        var body = component.get("v.body");
                        body.push(newComponent);
                        component.set("v.body", body);
                        compArr.push(newComponent);
                        component.set('v.compArray', compArr);
                    }
                    else if (status === "INCOMPLETE") {
                        console.log("No response from server or client is offline.");
                        // Show offline error
                    }
                }
            );  
        }
    }
},

Answer

I think based on the lightning bookshelf best practices its better to declare dependency for the component you are trying to create in the markup and create them again next time. This way it doesn’t go back to the server every time.

Except from Bookshelf:
Tip: There’s no limit in component creation on the client side. You can create up to 10,000 components in one server request.
If you hit this limit, ensure that you’re creating components on the client side in markup or in JavaScript using $A.createComponent()
or $A.createComponents(). To avoid a trip to the server for component creation in JavaScript code, add an tag for
the component in the markup to explicitly tell the framework about the dependency.

Also use the destroy method to explicitly destroy the component once its lifecycle is over.

Attribution
Source : Link , Question Author : Sarang , Answer Author : RedDevil

Leave a Comment