15

I would have expected that when a dynamically created lightning component is assigned as another component's attribute of type Aura.Component[], also referencing it in the parent component's markup by including something like {!v.attributeName}, then the parent component's JavaScript would be able to find that Facet by calling component.find() and passing in the aura:id value of the dynamically created component.

I have attempted this, but the result of the find() call is undefined. Code samples are below.

The parent component with the "stepData" facet... (created to test the stepData component during the development process)

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

<aura:handler name="completedActionFired" event="c:actionComplete" action="{!c.captureDataResult}" />
<aura:handler name="init" action="{!c.doInit}" value="{!this}"/>

{!v.stepData}

<!-- Include the SLDS static resource (adjust to match package version) -->
<ltng:require styles="{!$Resource.SLDS202 + '/assets/styles/salesforce-lightning-design-system.css'}"/>

<lightning:layout horizontalAlign="space">
    <lightning:layoutItem flexibility="grow" padding="horizontal-medium">
        <lightning:button variant="brand" label="Get Object Data" onclick="{! c.getObjectData }" />
        <br/><br/>
        <lightning:button variant="brand" label="Find Component and Get Object Data" onclick="{! c.findObjectData }" />
        <br/><br/>
    </lightning:layoutItem>
</lightning:layout>
</aura:component>

The parent component controller, where findObjectData() cannot find the Facet component by its aura:id, but getObjectData() can get it by using the attribute name...

({
doInit : function(component, event, helper) {
    var dataMap = {
        "testString" : "test value",
        "testMap" : {"key1":"value1", "key2":"value2"}
    };

    var attributes = {
        "aura:id" : "stepData",
        "dataMap": dataMap
    };

    $A.createComponents(
        [[ "c:stepData", attributes ]],
        function(results) {
            component.set("v.stepData", results[0]);
        }
    );
},
findObjectData : function(component, event, helper) {
    // try finding component by aura:id
    var stepData = component.find("stepData");
    if(stepData == null) {
        console.log('stepData is not found');
        return;
    }

    // try calling aura:method on stepData
    var result = stepData.getObject("testString");
    console.log(result);
},
getObjectData : function(component, event, helper) {
    // get stepData by accessing attribute
    var stepData = component.get("v.stepData")[0];
    console.log(JSON.stringify(stepData.get("v.dataMap")));

    // able to get dataMap attribute from stepData component
    var dataMap = stepData.get("v.dataMap");
    console.log(dataMap.testString);

    // able to call aura:method, but does not return any value to caller
    var result = stepData.getObject("testString");
    console.log(result);
}
})

Lightning Component Tree shows the aura:id included on the stepData component reference...

enter image description here

console log shows the "get" button clicked, then the "find" button clicked, where "stepData is not found" indicates find() and aura:id did not successfully locate the dynamically created Facet component. enter image description here

0

3 Answers 3

17

This is a bug inside the framework where dynamically created components are not getting properly indexed to their parents. Doesn't look like anyone is actively working on it right now. If you'd like to put some pressure on the devs who own this you can file a case and tell them to link the case to internal bug W-2529066.

4
  • Is there any news when this would be implemented? Spring 17 hopefully? Commented Jan 6, 2017 at 11:13
  • 2
    @joshuadelange The bug is still not fixed and currently targeted to the Summer '17 release. Commented Jan 6, 2017 at 18:26
  • 6
    I'd add to this that there is a workaround. All attributes of Aura.Component[] can be accessed via component.get("AttributeName"). If you want the value of the first item in the array you can do: var value = component.get("AttributeName")[0].get("v.value"); Commented Jan 11, 2017 at 23:17
  • 2
    @TrevorBliss I have just faced this problem in my sandbox, is this bug fixed? (we've passed summer 17...) Commented Jul 12, 2017 at 16:00
4

as @techbusinessman stated, the only workaround (so far) to get the value from a dynamically created component is to use :

var value = component.get("v.*attributeName*").get("v.value");// for type="Aura.Component" 

or

var value = component.get("v.*attributeName*")[0].get("v.value"); // for type="Aura.Component[]" 

posting it again so that it would help somebody. This small piece of bug has already eaten half of day when I found his comment.

3

Here's an alternative workaround which seems much neater to me (set as an answer because it gives space for the code)...

First declare an attribute to store dictionary object of aura:id to component:

<aura:attribute name="dynamicComponentsByAuraId" type="Object" />

Then, populate that object in the callback when you create your components:

    $A.createComponents(
        componentArray,
        function(newComponents, status, errorMessage){
            if (status === "SUCCESS") {
                var container = component.find("formContainer");
                var containerBody = component.get("v.body");

                var dynamicComponentsByAuraId = {};

                for(var i=0; i < newComponents.length; i++) {
                    var thisComponent = newComponents[i];
                    container.push(thisComponent);
                    dynamicComponentsByAuraId[thisComponent.getLocalId()] = thisComponent;
                }

                container.set("v.body", containerBody);

                console.log("dynamicComponentsByAuraId");
                console.log(dynamicComponentsByAuraId);
            }
        }
    );

Then, instead of calling component.find("foo"), you can just use:

var fooComponent = dynamicComponentsByAuraId["foo"];
// do things with fooComponent

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .