5

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
                    }
                }
            );  
        }
    }
},
  • Just a quick question, can you try an aura:iteration to render the components there instead of pushing them both to the array and to the body? – Sebastian Kessel Dec 28 '16 at 16:20
  • I've just stumbled upon Component.autoDestroy API property and thought of this question: could it be you need to set it false somewhere? See: eu5.lightning.force.com/auradocs/… – MLucci Jan 2 '17 at 16:12
1

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.

  • I am already using aura:dependancy. But on action of "on change " of a dropdown, this dynamic component creationn code is called again which is leading to server call everytime.So, what I want here is that how to store once dynamically created component into some array so that we can access them later w/o server call or by again creating them – Sarang Dec 30 '16 at 11:05
1
+25

Looking at the piece below, it looks like you're first invalidating all existing code in what I marked as "Line 1", then you're getting that invalid code in "Line 2" and pushing a new object to it in "Line 3".

It feels, based on this code (it also feels I am lacking information), that you are clearing the body before adding the new object, which should either delete or invalidate everything that was in the body before. Based on your question, it doesn't look like that's the objective.

        var body = component.get("v.body");
        component.set("v.body", []); **LINE 1
        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"); **LINE 2
                        body.push(newComponent); 
                        component.set("v.body", body); **LINE 3
                        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
                    }
                }
            );  
        }
  • yes, every time I come into this method, first thing I want to do is clear the screen of whatever is rendered till now. So I am clearing the body and then adding new component dynamically to body (as well as to "compArr")based on new input from user. SO do you mean here that because I clear body of component, the components stored in Aura.Component[] also become invalid? – Sarang Dec 29 '16 at 5:39
  • I think your logic is messed up. In Line 1 you empty out the body. In line 2 you GET it (but it's empty now, because of Line 1) and then you try to add one thing to it. This means that the body will never have more than 1 item in it. – Sebastian Kessel Dec 29 '16 at 17:38
  • That is what I want...I want body to have 1 component at a time in it. BUT, I want to save components somewhere else(that is in compArr i.e Aura.component[]) so that I can reuse them without CREATING them dynamically again through call back function – Sarang Dec 30 '16 at 6:05
  • And hence the question above: "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?".... I hope I am clear in my query...thanks in advance! – Sarang Dec 30 '16 at 6:06

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.