extending lightning components

I would like to find out which cases are appropriate for using inheritance in lightning components, particularly how can we use polymorphism by extending lightning componets or maybe implementing custom interfaces? As far as I know according to this article https://developer.salesforce.com/blogs/developer-relations/2015/03/salesforce-lightning-components-by-example-component-extension.html we can only inherit parent attributes and helper methods

e.g.

parent

<aura:component extensible="true" abstract="true" controller="ObjectPanelController">
   <aura:attribute name="sObjectType" type="String" required="true" />
<aura:attribute name="maxRows" type="Integer" default="20" />
<aura:attribute name="fields" type="String" />
<aura:attribute name="records" type="Object[]" />
<aura:attribute name="sObjectInfo" type="Object" />
</aura:component>

helper:

  navigateToRecord : function(component, event, helper) {    
        ///
    },
    deleteRecord : function(component, event, helper) {
       ////
    }

Child

<aura:component extends="c:objectPanel">  
    <aura:set attribute="sObjectType" value="Account" />
    <aura:set attribute="fields" value="AccountNumber,Website" /> 
            <a onclick="{!c.deleteRecord}">Del</a> | 
            <a onclick="{!c.navigateToRecord}">navigate</a>

</aura:component>

Controller

({
    navigateToRecord : function(component, event, helper) {    
        helper.navigateToRecord(component);//calls parent helper
    },
    deleteRecord : function(component, event, helper) {
        helper.deleteRecord(component); //calls parent helper
    }
})

Could we have other reasonable use cases of inheritance with using polymorphism for instance something like this

<aura:attribute name="MainComponent" type="Object[]" />
 <aura:iteration items="{!v.MainComponent}" var="main">
   {!main}
// particular instance that extends MainComponent
 </aura:iteration>

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

I have also started using inheritance + interfaces to remove boilerplate and leverage a consistent codebase.

I use many of the same techniques and also add in in Notifers and Spinners to get a nice consistent messaging framework (I note that I’ve seen a better implementation of spinners than mine by using the doneWaiting and waiting system events, so you might want to take that into consideration if implementing some of my example code.

My interface looks a little like this:

<aura:interface description="Interface that enforces the use of certain events and attributes">

  <aura:attribute name="opportunityId" type="String" description="Id of the Opportunity "/>
  <aura:attribute name="componentId" type="String" description="Id of this component, which should match the aura:id"/>

  <aura:registerEvent name="someCommonEvent" type="c:MySharedEvent"/>

</aura:interface>

My abstract component looks like this:

<aura:component  abstract="true" extensible="true" >
  <aura:handler name="init" value="{!this}" action="{!c.init}" />
  <aura:method name="refresh" action="{!c.reInit}"/>

  <c:Notifier aura:id="notifier" />
  <c:Spinner aura:id="spinner" />

  <!-- body of sub components -->
  {!v.body}

</aura:component>

Inside the Abstract helper, here is some of the code:

showSuccessAlert: function(message, component) {
  var notifier = component.getSuper().find('notifier');
  notifier.showSuccess(message, true, 3000);

},
showErrorAlert: function(message, component) {
  var notifier = component.getSuper().find('notifier');
  notifier.showError(message);
},

callServerMethod: function(component,apexMethodName,apexParams,successCallBack,errorCallBack) {

  var superSelf = this;

  if (!apexMethodName ){
    superSelf.showErrorAlert("Helper Error: no method name supplied");
    return;
  }
  ....
}

Finally, components extending the Abstract component can make server calls, show and hide spinners very easily as shown here:

saveData: function(component) {
  self = this;
  self.showHideSpinner(true,component);
  this.callServerMethod(
    component,
    'c.saveData',                        //apexMethodName
    {data: somedata},                    //apexParams
    function(result){                    //successCallBack
      self.postSaveActions(component);
    },
    null
  );
},

Most of this code is available on Github here

Note, in the Github version, I also have an interface and a common message format between Apex and Lightning that you may or may not want to use – it simplifies data transfer between back and front end, but does impose some restrictions that you might not like.

Method 2

We use inheritance extensively in our work places. some of the use cases for extending a base lightning component kind are if you have some functions that you want to use in multiple components.

Lets say in your first component you have a method called callserver which makes a server call and returns the response. all your components which needs server interaction will need this method so instead of writing logic to call server in each and every helper you can write it in the abstract component and all the other methods can extend it. So in our case it takes parameters
1.Component instance
2.Server method name
3.Params
4.Callback function
5.cacheable property

So when other components extend this component we do this.callserver(); from them to re-use this function. All the logic related to calling server checking for status success,error and then incase of errors showing a error banner happens in the abstract method. This way we increase re-usablility and in future if SF change definition of server call we just change it one place and it will work fine across all the components.

For Interfaces we have lot of components which have pagination kind of functionality. they have kind of similar parameters like firstpage,lastpage,currentpage. so instead of re-creating them in each and every component we created a interface for it and re-use it across components.

All re-usable methods we need across multiple components we put it on the abstract component and re-use them across components by extending it. In the longer run these methods will get time tested and will become robust and that will result in a very stable solution.

Some of the reusable methods we have are
1.Calling server
2.Parsing URL parameters
3.Custom console.log function instead of javascript console.log to control them from one place
4.merging null value fields with sobjects attributes since SOQL doesnt return null fields back to lightning components.

Hope this helps!

If you need specific code examples i can post that as well if its going to help you.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x