[SalesForce] Component.find() Called From Child Extending an Abstract Component Fails

I was hoping to set up an abstract component with some useful markup (custom spinner and notifier components in this instance) that could be extended by other components.

The structure would be:

AbstractComponent
AbstractMarkup
Body of Extending Component

However, when I call a method on the abstract component, it is unable to find any of it's own components. I think this is an error, because it makes the abstract component much less useful.

Here is code that will replicate the issue:

TestFindAbstract.cmp

<aura:component abstract="true" extensible="true" >
    <ui:outputText value="hey" aura:id="myText"/>
    {!v.body}
</aura:component>

TestFindAbstractHelper.js

({
    changeText : function(component) {
        var text = component.find("myText");
        text.set("v.value","New Text");
    }
})

Now, the extending class:

TestFind.cmp

<aura:component extends="c:TestFindAbstract">
    <lightning:button label="Press Me" iconName="utility:download" iconPosition="left" onclick="{!c.changeText}" /> 
</aura:component>

TestFindController.js

({
    changeText : function(component, event, helper) {
    helper.changeText(component);
    }
})

I would have expected the extending class to call the method on the abstract class, find the component and change the value.
Instead, I get the very diplomatic error message:

This page has an error. You might just need to refresh it.
Action failed: c$TestFind$controller$changeText [Cannot read property 'set' of undefined]
Failing descriptor: {c$TestFind$controller$changeText}

Any insights would be appreciated!

Best Answer

You can solve this in two ways:

  1. Since the ui:outputText belongs to the extensible component, you need to get hold of the super component; then from there find and set ui:outputText's value.

With the above change, your helper will look like this:

({
    changeText : function(component) {
        var text = component.getSuper().find("myText");
        text.set("v.value","New Text");
    }
})
  1. Define an aura:attribute in the extensible component, and set its value in the concrete component.

TestFindAbstract.cmp:

<aura:component abstract="true" extensible="true" >
    <aura:attribute name="text" type="String" default="hey" />
    <ui:outputText value="{!v.text}" aura:id="myText"/>
    {!v.body}
</aura:component>

TestFindCmp.cmp:

<aura:component extends="c:TestFindAbstract">
    <lightning:button label="Press Me" iconName="utility:download" iconPosition="left" onclick="{!c.changeText}" /> 
</aura:component>

TestFindCmpController.js:

({
     changeText : function(component, event, helper) {
         component.set("v.text",'New');
    }
})
Related Topic