[SalesForce] 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>

Best Answer

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.

Related Topic