8

Is it possible to dynamically create a lightning component and put it into a custom lightning component?

For example, I have the following custom lightning component:

<aura:component>
    <div class="wasCreatedDynamicallyInCode">
        Here should go the component:
        <div id="addALightningComponentHere">

        </div>
    </div>
</aura:component>

And I have a component which statically I would add in the following way:

<aura:component>
    <div class="wasCreatedDynamicallyInCode">
        Here should go the component:
        <div id="addALightningComponentHere">
            <namespace:MyComponent myArg="{!v.myArg}"/>
        </div>
    </div>
</aura:component>

How could I add the line <namespace:MyComponent myArg="{!v.myArg}"/> dynamically from client-side controller?

I am aware of everything written here. It does not help me to solve the problem, so I am posting it here.

UPDATE

In order to show why addition of {!body} confuses me I will tweak the code a little bit.

<aura:component>
    <div class="wasCreatedDynamicallyInCode">
        Here should go the first component:
        <div id="addALightningComponentHere1">
            <namespace:MyComponent myArg="{!v.myArg}"/>
        </div>
    </div>
    <div class="wasCreatedDynamicallyInCode">
        Here should go the second component:
        <div id="addALightningComponentHere2">
            <namespace:MyComponent myArg="{!v.myArg}"/>
        </div>
    </div>
</aura:component>

Not only the component I am setting in place of {!v.body}, but also the {!v.body} and aura:id for encompassing element should be generated at runtime.

  • Yes it is and the link you have included includes the relevant material. Where are you stuck? – Keith C Sep 9 '18 at 17:36
  • @KeithC, could you, please, provide a JavaScript code to accomplish this? Since I can follow only examples in documentation and do not know how to add the component without having a {!v.body}. – hellohowdoyoudo Sep 9 '18 at 17:37
  • What is stopping you adding a {!v.body}? – Keith C Sep 9 '18 at 17:39
  • @KeithC, I can have multiple places in my custom lightning component where I would like to add another lightning component. Let me update the question to elaborate this. – hellohowdoyoudo Sep 9 '18 at 17:49
  • You're allowed to have more than one facet (attribute of type Aura.Component[]), beyond just v.body. – David Reed Sep 9 '18 at 17:59
14

A Lightning attribute like v.body, which is typed as Aura.Component[], is called a facet. It's perfectly legal to have multiple facets in your component.

You'd have to do something more like this, if I may modify your example component to suit. Note the Aura.Component[]-typed attributes: these behave like v.body in that they hold dynamically-instantiated Lightning components, but you can place them as you please and have more than one as needed.

<aura:component>
    <aura:attribute type="Aura.Component[]" name="firstPanel" />
    <aura:attribute type="Aura.Component[]" name="secondPanel" />
    <aura:handler name="init" value="{! this }" action="{! c.doInit }" />
    <div class="wasCreatedDynamicallyInCode">
        Here should go the first component:
        <div id="addALightningComponentHere1">
            {! v.firstPanel }
        </div>
    </div>
    <div class="wasCreatedDynamicallyInCode">
        Here should go the second component:
        <div id="addALightningComponentHere2">
            {! v.secondPanel }
        </div>
    </div>
</aura:component>

Then, in your JavaScript controller, you'd do something like the below (adapted from the linked documentation, and omitting error handling and action handler body for clarity):

({
    doInit : function(cmp) {
        $A.createComponent(
            "lightning:button",
            {
                "aura:id": "findableAuraId",
                "label": "Press Me First",
                "onclick": cmp.getReference("c.handlePress")
            },
            function(newButton, status, errorMessage){
                //Add the new button to the body array
                if (status === "SUCCESS") {
                    var firstPanel = cmp.get("v.firstPanel");
                    firstPanel.push(newButton);
                    cmp.set("v.firstPanel", firstPanel);
                }

            }
        );
        $A.createComponent(
            "lightning:button",
            {
                "aura:id": "findableAuraId",
                "label": "Press Me Second",
                "onclick": cmp.getReference("c.handlePress")
            },
            function(newButton, status, errorMessage){
                //Add the new button to the body array
                if (status === "SUCCESS") {
                    var secondPanel = cmp.get("v.secondPanel");
                    secondPanel.push(newButton);
                    cmp.set("v.secondPanel", secondPanel);
                }

            }
        );
    },
    handlePress: function(component, event, helper) {

    }
})

Now, if what you need is a dynamically determined number of dynamic component slots in something like an iteration, that might be a situation that calls for decomposing this component into a suite of more elemental components (which themselves might or might not contain facets) rather than building it all into a single massive component, or following the example (again in the linked documentation) that dynamically instantiates children of dynamically instantiated components.

That said, in most cases it seems to be better design to decompose components and conditionally render rather than using very deep dynamic instantiation.

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.