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

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.

  • Is there any news when this would be implemented? Spring 17 hopefully? – joshuadelange Jan 6 '17 at 11:13
  • 2
    @joshuadelange The bug is still not fixed and currently targeted to the Summer '17 release. – TrevorBliss Jan 6 '17 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"); – techbusinessman Jan 11 '17 at 23:17
  • 2
    @TrevorBliss I have just faced this problem in my sandbox, is this bug fixed? (we've passed summer 17...) – Itai Shmida Jul 12 '17 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

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.