extending lightning components

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.


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.