= The inheritance of components and the usage of interfaces is usually not explained at a greater detail when it comes to the majority of the samples we find as the google results are focussed on giving a basic idea. may be I am searching wrong. So am summarizing it here, please feel free to comment or clarify and I will update this doc accordingly.
References :
- Reusable lightning components by AutomaTom
- Github repo for Scheduler
- Reusable lightning components by John Belo
- Interface reference
- Aura Components not necessarily in lightning components
cmp1.cmp
<aura:component>
{!v.body}
</aura:component>
cmp2.cmp
<aura:component>
This is the dummy text inside component2
</aura:component>
TestApp.app
<aura:application>
<c:cmp1>
<c:cmp2 />
</c:cmp1>
</aura:application>
To see the definition of cmp2 , the cmp1 definiton should have a line at the end {!v.body}
body attribute refers to the content which is wrapped inside a component. ex:
<cmp1>
Everything that is here is part of body attribute.
</cmp1>
so in my component definition if i dont have the line
<aura:component>
<!-- {!v.body} -->
</aura:component>
Anything wrapped inside will not be displayed.
<aura:component>
<aura:method action="{!c.controllerMethod}" name="doControllerMethod">
<aura:attribute name="name" type="String" />
<aura:attribute name="arguments" type="Object[]" />
</aura:method>
</aura:component>
This is a publicly accessible method as part of the component. at any point am able to get the component definition , I will be able to access the controller method directly.
I am gonna have 3 components
- baseSearch
- has searchstring and searchResults
- orchestrates how the helper methods are called.
- advSearch
- has one text box for searching
- implements the missing method from baseSearch
- moreAdvSearch
- has one button to submit for searching
- tries to call the search method which is shared with helpers.
baseSearch.cmp
<aura:component extensible="true" abstract="true">
<aura:attribute type="String" name="searchString" access="public" />
<aura:attribute type="Object[]" name="searchResults" access="public" />
<aura:method name="doSearch" action="{!c.doSearch}" access="public">
<aura:attribute name="name" type="String" />
<aura:attribute name="arguments" type="Object[]" />
</aura:method>
{!v.body}
</aura:component>
This is the place we should expand our understanding of the "helper" inside lightning components.
baseSearchController.js
({
doSearch : function(component, event, helper) {
var params = event.getParam("arguments");
/*
we need a detailed understanding of apply function of javascript
it was confusing for me until i saw this example.
*/
helper[params.name].apply(helper, params.arguments);
}
})
baseSearchHelper.js
({
test:function(){
//since the component is abstract,
//I can define my helper methods in one of the extended ones.
//but its important that helper object is not empty , it has atleast 1 function at the base component.
}
})
advSearch.cmp
<aura:component extends="c:baseSearch" extensible="true">
<ui:inputText class="slds-input" value="{!v.searchString}" />
{!v.body}
</aura:component>
advSearchController.js
({
//its empty
})
advSearchHelper.js
({
//the name baseHelperMethod is important for us to know which function to call from one of the children.
// since the baseSearch is a abstract component this is where we implement the definition.
baseHelperMethod : function(component) {
//instead of getting results ,am populating some dummy after 5 seconds.
window.setTimeout(
$A.getCallback(function(){
if(component.isValid()){
component.set('v.searchResults',[{'a':'b','c':'d'},{'a':'b5','c':'d5'},{'a':'b4','c':'d3'},{'a':'b2','c':'d2'},{'a':'b1','c':'d1'}]) ;
}
}),5000
);
}
})
moreAdvSearch.cmp
<aura:component extends="c:advSearch">
<ui:button label="Search Advanced" press="{! c.doSearchTest }" />
<aura:iteration items="{!v.searchResults}" var="searchResult">
{!searchResult.a} - {!searchResult.c} <br />
</aura:iteration>
</aura:component>
moreAdvSearchController.js
({
doSearchTest : function(component, event, helper) {
// previously we had access to the helper functions of the parent components directly but
// after locker service is enabled we have to go through the workaround of
// calling a public method which calls the helper method from base component.
component.getSuper().doSearch('baseHelperMethod',[component.getSuper()]);
}
})
Interface at a high level helps us define a specific group of functionality that every component can chose to implement in its own way.
ex: a quick action, if a component is implementing a force:lightningQuickAction or force:lightningQuickActionWithoutHeader , this enables us to configure custom quick actions.
$A.get("e.force:closeQuickAction");
$A.get("e.force:closeQuickAction");
are available directly on the component controller/helper without registering them separately.
These are advantages of using platform specific quick actions , but we also create our own interfaces. now hold on , you may ask why do we need to do that ?
They dont have any additional functionality other than attributes and registered events , we can as well have that code in our component.One of the biggest temptations of procedural programming.
Lets dive into an example.