6

I have a Parent component rendering child components. I want this to happen dynamically, meaning that I can pass in a child component definition and fill it with data afterwards.

<!--c:child-->
<aura:component extends="c:abstractChild">
    Hello World
</aura:component>

<!--c:parent-->
<aura:component>
    <aura:attribute name="child" type="Aura.Component[]"/>
    {!v.child}
</aura:component>

<!--c:container-->
<aura:component>
    <c:parent>
        <aura:set attribute="child" >
            <c:child />
        </aura:set>
    </c:parent>
</aura:component>

It works fine. Now I want something like this:

<!--c:child-->
<aura:component>
    <aura:attribute name="fooBar" type="Object" />
    {!v.fooBar}
</aura:component>

<!--c:parent-->
<aura:component>
    <aura:attribute name="child" type="Aura.Component[]"/>
    <aura:attribute name="fooBarList" type="Object"/>

    <aura:iteration items="{!v.fooBarList}" var="fooBar">
        {!v.child}
        <!--<aura:set attribute="fooBar" value="{!fooBar}"/>-->
    </aura:iteration>
</aura:component>

(The fact that I need it in a loop is important. So I can't set the attribute in my component controller.)

How do I set attributes for this child in my Parent component?

type="Aura.Component[]" is not typed, can I pass in something like a typed component? Or do anything to convert attributes back to components?

Pseudo code:

<aura:attribute name="child" type="c:child"/>

<aura:dynamic component="{v.child}">
    <aura:set attribute="fooBar" value="{!fooBar}"/>
</aura:dynamic>
0

Unless I'm totally missing what you're trying to do here, I think you need to use $A.createComponents() to create them dynamically from the controller/helper of c:parent.

c:parent could take a list of objects describing what it needs to create e.g.

spec = [ {type: 'c:Child1', attr1: 'foo'}, {type: 'c:Child2', attr2: 'bar'} ]

Then, in the parent, do something like this:

var componentArray = [];
spec.forEach(function (thisSpec) {
  componentArray.push([thisSpec.type, thisSpec]);
});

$A.createComponents(componentArray, function(newComponents, status) {
  if(status === 'SUCCESS') {
    var body = component.get('v.body');
    body = body.concat(newComponents);
    component.set('v.body', body);
  }
});

You can later check that the children are instances of c:abstractChild by using component.isInstanceOf('c:abstractChild')

Disclaimer: I haven't run that code, but I have production code doing roughly the same thing, so it ought to at least give you the gist of what to do.

3
  • Thanks for your answer, but creating the components in the controller won't work for me, since $A.createComponents just creates them, but I have a complex structure (table), that needs to be rendered in the markup. Else I would have to run through the whole data and replace it with component definitions.
    – Basti
    Oct 25 '17 at 14:18
  • It's up to you to decide where you insert the dynamic components after they are created. They don't just have to replace the body - you could find some part of a table and insert them there. Or you could put in placeholders with aura:iterations, then overwrite them once you've created the right type. Can you add to your question to explain why the table part is significant?
    – Aidan
    Oct 25 '17 at 14:28
  • Well I'm having a table with rows, columns and summaries all of them containing cells or at least references and I don't want to duplicate this structure to rerender the markup. It just feels to dirty, I wouldn't need an OOP approach, when I start hacking things in my controller. I really appreciate your contribution and it triggers new thoughts, but doing all the important stuff in the controller is not an option for me.
    – Basti
    Oct 25 '17 at 14:49

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.