So, after a lot of struggle, I think I found a solution so Template components can work with Locker Service and call helpers of components who instanciate them , using aura:method but without having to describe 10000 times each method.
To do that, the template component must inherit from a component CmpTemplateRoot , as described in the post.
Even if it seems to works correctly, my worries are :
I feel it's dirty to use a component attribute as buffer for function return value
I use inheritance on Cmp JS controller: in the doc it says not to do it, so the day it's killed, my solution won't work anymore.
I really would prefer a clean solution directly in the framework to access child helper from template component code, is it really impossible for SalesForce to implement that ? Doug Chasman u said "The pattern your using looks like https://en.m.wikipedia.org/wiki/Template_method_pattern, correct? We do need a supported way to implement that very useful pattern. " ... isn't there other ways to use it, with a detailed example ?
CmpTemplateRoot: to just copy-paste in your org, then if you make your components inherit from it, you can call method callConcreteCmpHelper: (component,HelperFunctionName,HelperFunctionParams) from a Template component helper to access child component helper methods.
Cmp:
<aura:component extensible="true" abstract="true" access="global" >
<aura:method name="callCmpHelper" action="{!c.callCmpHelper}">
<aura:attribute name="HelperFunctionName" type="String" />
<aura:attribute name="HelperFunctionParams" type="Object" />
</aura:method>
<aura:attribute name="HelperMethodResultList" type="Object" description="Buffer parameter to store instanciated component helper methods result"/>
{!v.body}
</aura:component>
JS controller:
({
// NVU: Template component calling the instanciated component helper
// The "this" of this method is the component instanciation of the template component
callCmpHelper : function(component, event, helper) {
var params = event.getParam('arguments');
var HelperFunctionName = params.HelperFunctionName ;
var HelperFunctionParams = params.HelperFunctionParams ;
var HelperFunctionResult = helper[HelperFunctionName].apply(helper,HelperFunctionParams);
// As aura:method can not return value, store return value in "buffer" attribute HelperMethodResultList.
// Will be retrieved by template component method callConcreteCmpHelper
if (HelperFunctionResult != null)
{
var HelperMethodResultList = component.get('v.HelperMethodResultList');
if (HelperMethodResultList == null)
HelperMethodResultList = {};
HelperMethodResultList[HelperFunctionName] = HelperFunctionResult;
component.set('v.HelperMethodResultList',HelperMethodResultList);
}
}
})
JS Helper:
({
// NVU: This method can be called to access helper methods of inherited components
// The "this" of this method is the template component
callConcreteCmpHelper: function (component,HelperFunctionName,HelperFunctionParams) {
var ConcreteComponent = component.getConcreteComponent();
ConcreteComponent.callCmpHelper(HelperFunctionName,HelperFunctionParams);
// Get return value in "buffer" attribute
var HelperMethodResultList = component.get('v.HelperMethodResultList');
if (HelperMethodResultList == null)
HelperMethodResultList = {};
if (HelperMethodResultList[HelperFunctionName] != null)
return HelperMethodResultList[HelperFunctionName] ;
}
})
Here is an example of using :
CmpDummyRoot "Template component"
Cmp
<aura:component extensible="true" abstract="true" extends="irm:CmpTemplateRoot" access="global">
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
<aura:attribute name="DummyVal" type="String" />
My template component CmpDummyRoot displays the value <strong>"{!v.DummyVal}"</strong> returned by child component CmpDummyChild instanciating this template component
</aura:component>
JS Controller:
({
doInit : function(component, event, helper) {
helper.myMasterMethodHlp(component,event);
}
})
JS Helper:
({
myMasterMethodHlp : function(component,event) {
var DummyVal = this.callConcreteCmpHelper(component,'myChildMethodHlp',[component,event]);
component.set('v.DummyVal',DummyVal);
}
})
"Child component using the template component" CmpDummyChild
Cmp:
<aura:component extends="irm:CmpDummyRoot">
</aura:component>
Helper:
({
myChildMethodHlp : function(component,event) {
var ChildDummyVal = 'ValComingFromChildHelper!!';
return ChildDummyVal;
}
})