Lightning component.find("aura:id") returns an array consisting of one element
The reason only one item could be returned as the result of a find() call is that we keep a map of ID to component in our services.
"myId": "1:0"
If you register two components with the same ID, we convert it to an array.
"myId": ["1:0", "42:0"]
If you then destroy one of those components, it stays an array.
"myId": ["1:0"]
I do think there might be a bug on this, but I'm just here explaining what happened.
Okay, this seems to be because of how aura:id is cached and the Lightning life cycle. Here's a reproduction of the problem:
<aura:application >
<aura:attribute name="dyn" type="Aura.Component[]" />
{!v.dyn}
<hr />
<ui:button press="{!c.dynamicReset}" label="Reset" />
</aura:application>
({
dynamicReset: function(component, event, helper) {
console.log("Reset");
$A.createComponents(
[["ui:outputText",{"aura:id":"a1","value":"Hello World"}]],
function(cmp, stat, err) {
component.set("v.dyn", cmp);
console.log("Immediate check");
helper.showoutput(component);
setTimeout($A.getCallback(function() {
console.log("Delayed Check");
helper.showoutput(component);
}));
}
)
}
})
({
showoutput: function(component) {
let res = component.find("a1");
if(res) {
if(res.length) {
let output = "Array of "+res.length+" ";
res.forEach(function(v,i) {
output = output + i + " Valid: " + v.isValid()+" ";
});
console.log(output);
} else {
console.log("One Component Found");
}
}
}
})
This ultimately results in output that looks like this:
Reset
Immediate Check
One Component Found
Delayed Check
One Component Found
Reset
Immediate Check
Array of 2 0 Valid: true 1 Valid: true
Delayed Check
Array of 1 0 Valid: true
Conclusion: It seems that however aura:id is being cached, it results in bugs by finding components that exist but are no longer part of the component hierarchy, and/or results in an array being created instead of immediate removal.
You can fix this by introducing a life cycle delay:
({
dynamicReset: function(component, event, helper) {
console.log("Reset");
component.set("v.dyn", null);
setTimeout($A.getCallback(function() {
$A.createComponents(
[["ui:outputText",{"aura:id":"a1","value":"Hello World"}]],
function(cmp, stat, err) {
component.set("v.dyn", cmp);
console.log("Immediate check");
helper.showoutput(component);
setTimeout($A.getCallback(function() {
console.log("Delayed Check");
helper.showoutput(component);
}));
}
)}));
}
})
By setting it to null and allowing it to propagate, the one-element-array doesn't occur:
Reset
Immediate Check
One Component Found
Delayed Check
One Component Found
Reset
Immediate Check
One Component Found
Delayed Check
One Component Found