Wednesday, December 15, 2021

Lightning component framework event handling lifecycle

 The framework uses event-driven programming. You write handlers that respond to interface events as they occur. The events may or may not have been triggered by user interaction. In the Lightning Component framework, events are fired from JavaScript controller actions. Events can contain attributes that can be set before the event is fired and read when the event is handled. Events are declared by the aura: event tag in a .evt resource, and they can have one of two types: component or application.

Component Events

A component event is fired from an instance of a component. A component event can be handled by the component that fired the event or by a component in the containment hierarchy that receives the event.

Application Events

Application events follow a traditional publish-subscribe model. An application event is fired from an instance of a component. All components that provide a handler for the event are notified.

Always, try and use component events over application events for an effective containment hierarchy. Now WTH is containment hierarchy? It is a tree of components that has a top-level container as its root.  Events are fired by user actions and events which are results of actions and are different from app and comp events mentioned above. There are also System events that is fired automatically by the framework during its lifecycles, such as during component initialization, change of an attribute value, and rendering. 

Assuming that you have some basic knowledge of Lightning events, lets Dig deeper into Component and application events.

Component Event Propagation

The framework supports capture and bubble phases for the propagation of component events similar to DOM handling patterns. This gives an opportunity for interested components to interact with an event and potentially control the behavior for subsequent handlers.

The component that fires an event is known as the source component. The framework allows you to handle the event in different phases. These phases give you flexibility for how to best process the event for your application. Here is the phases and sequence of component event propagation:

  1. Event fired—A component event is fired.
  2. Capture phase—The framework executes the capture phase from the application root to the source component until all components are traversed. Any handling event can stop propagation by calling stopPropagation() on the event.
  3. Bubble phase—The framework executes the bubble phase from the source component to the application root until all components are traversed or stopPropagation() is called.

Lightning component events also support both capture and bubble phases, but there are some framework specificities in terms of syntax and behavior. By default, component events are handled in the bubble phase, and that’s what most developers use. To handle the capture phase, add a phase=”capture” attribute to your event handler, like so:

<aura:handler name="cmpEvent" event="c:cmpEvent" action="{!c.handleCmpEvent}" phase="capture"/>

You two handlers to use both the phases and query the event’s current propagation phase by calling event.getPhase() in your event handling function which in-turn will either return capture or bubble. By default , in Lightning component hierarchy only parent components that create subcomponents (either in their markup or programmatically) can handle events which does not include container components.

Lets take the below example:

<!-- c:cmp1 -->
<aura:component>
    <c:cmp2>
        <c:cmp3>
    </c:cmp2>
</aura:component>

Here, an event transmitted by cmp3 can not be handled by cmp2 as its not the outermost component. However, cmp2 can handle it a sits the outermost component and includes cmp2 and cmp3. If you want a container component cmp2 to handle a component event, add an includeFacets=”true” attribute to its handler, such as:

<!-- c:containerCmp -->
<aura:component>
    <aura:handler name=“cmp3” event=“c:cmp3” action="{!c.handleCmpEvent}" includeFacets="true"/>
    {!v.body}
</aura:component>


You can stop the event at any point by calling event.stopPropagation() regardless of the current propagation phase. This is not a best practice as other components won’t be able to handle the vents once stopped. Lightning Framework also gives us an option to resume and pause the event which can be a typical use case for this is asynchronous processing.

handleEvent:function(component, event, helper){
event.pause();
Var action = $component.get(“c.getABeer”);
action.setcallback(this, function(response){
if(response.getState() == “SUCCESS”) {
event.resume();
}  else if (state === "ERROR") {

      event.stopPropagation();
    }
});


}

_config.yml

Look at the example given in the documentation here.

Application Events

Application events follow a traditional publish-subscribe model. An application event is fired from an instance of a component. All components that provide a handler for the event are notified. Here is the phases and sequence of application event propagation:

  1. Event fired—An application event is fired. The component that fires the event is known as the source component.
  2. Capture phase—The framework executes the capture phase from the application root to the source component until all components are traversed. Any handling event can stop propagation by calling stopPropagation() on the event.
  3. Bubble phase—The framework executes the bubble phase from the source component to the application root until all components are traversed or stopPropagation() is called.
  4. Default phase—The framework executes the default phase from the root node unless preventDefault() was called in the capture or bubble phases. If the event’s propagation wasn’t stopped in a previous phase, the root node defaults to the application root. If the event’s propagation was stopped in a previous phase, the root node is set to the component whose handler invoked event.stopPropagation().

Rest of the story remains the same as component events. You can find the example here.

Event Handling Lifecycle

The following chart from the developer documentation summarizes how the framework handles events:

_config.yml


Communications between Lightning Components : Salesforce

Salesforce have new lightning framework to create components in lightning framework which is fast with high performance to pass data from one lightning component to another. For this salesforce provides various ways to communicate between lightning components.

Below are the list of ways you can communicate :-

      1. Using attribute in lightning components.
      2. Using aura:method to pass data.
      3. Using component type event.
      4. Using application type event.
      5. Using System Events.

1. Using Attributes :-

we have a parent component in which we have a Boolean attribute which i want to pass to child component for further processing.


c:parentComponent.cmp
<aura:component>
<aura:attribute name=”showTable” default=”false” type=”boolean”/>
<lightning:button label=”show table” onclick=”{! c.showBoolean }” />
<c:childComponent tableDisplay=”{!v.showTable}”/>
</aura:component>

c:parentComponent.controller.js
({
showBoolean : function (component, event, helper) {
component.set(“v.showTable”, true);
}
})

c:childComponent.cmp

<aura:component>
<aura:attribute name=”showTable” type=”boolean” default=”false”/>
<aura:if isTrue=”{!v.showTable}”>
SHOW DATA TABLE HERE
</aura:if>
</aura:component>

we click on the lightning:button, it calls showBoolean method in parent component controller where we set the showTable attribute as true. In the code below lightning:button, we call child component and tag the tableDisplay attribute of child component with showTable on parent component. Now any changes in showTable attribute will be passed to showTable attibute of child component directly.

2. Using aura:method :-

We can call a child component method and pass the parameters to the child component using aura:method. For example we have a parent component from where we have to send data to a child component.


c:parentComponent.cmp
<aura:component>
<aura:attribute name=”showTable” default=”false” type=”boolean”/>
<lightning:button label=”show table” onclick=”{! c.showBoolean }” />
<c:childComponent aura:id=”childComponent”/>
</aura:component>

({
showBoolean : function (component, event, helper) {
var childComp = component.find(“childComponent”);
childComp.displayTable(component.get(“v.showTable”));
}
})

c:childComponent.cmp

<aura:component>
<aura:attribute name=”showTable” type=”boolean” default=”false”/>
<aura:method name=”displayTable” action=”{!c.showDataTable}”>
<aura:attribute name=”parameter1″ type=”boolean” default=”false”/>
<aura:method/>
<aura:if isTrue=”{!v.showTable}”>
SHOW DATA TABLE HERE
</aura:if>
</aura:component>

c:childComponent.controller.js
({
showDataTable : function(component, event, helper) {
var parameterList = event.getParam(“arguments”);
if(parameterList) {
component.set(“v.tableDisplay”, parameterList.parameter1);
}
}
})

we click on the lightning:button, it calls showBoolean method in parent component controller where we first find the childComponent using aura:id. Once we get the instance of childComponent we call aura:method function in childComponent whose name is displayTable with parameters in the function.

Lightning framework is based on event-driven architecture which allows to communicate between different events. Lightning events can be fired or handled by javascript controller. Event are triggered by user action.

As we know that along with system events, there are 2 types of custom lightning events:

      Application Events
      Component Events

3. Using component type event :-

Component events: to talk to a parent using the capture and bubbling mechanism, like with DOM events.Components events can be handled by same component or component which is present in containment hierarchy (component that instantiates or contain component).


Create New Event with String Param (MessageEvent)
<aura:event type="COMPONENT" description="Event template">                                         
<aura:attribute name="msg" type="String" access="GLOBAL"/>                                               
</aura:event>

You would then declare myEvent on the component as:
<aura:registerEvent name="message" type="c:MessageEvent"/>

Firing component events from javascript controller

var MessageEvent = component.getEvent("message"); 
MessageEvent.setParams({"msg":"New Message!!!."});                               
MessageEvent.fire(); 



While handling component events, we need to specify name attribute in  <aura:handler>

<aura:handler action="{!c.handleNotification}" event="c:MessageEvent" name="message">

Note : Make sure that name attribute is same as that of name attribute while registering the event.


Application events: This kind of events can be handled by any component which is listening to it (have handler defined for event). It is kind of publish-subscribe modal.


Creating application event. (MessageEvent)
<aura:event type="APPLICATION" description="Event template">                                                       
<aura:attribute name="msg" type="String" access="GLOBAL"/>                             
</aura:event> 

You would then declare myEvent on the component as:
<aura:registerEvent name="message" type="c:MessageEvent"/>
Firing component events from javascript controller

var appEvent = $A.get("e.c:MessageEvent");               
appEvent.setParams({"msg":"New Message!!!."});                                               
appEvent.fire(); 


While handling component events, we need to specify name attribute in  <aura:handler>

<aura:handler action="{!c.handleNotification}" event="c:MessageEvent" name="message">


3. Using System Events :-

System events: These events are fired automatically by the framework such as during component initialization, attribute value change, rendering etc. All Components can register for system events in their HTML markup.
Few examples of system events are init, aura:waiting, aura:doneWaiting, aura:doneRendering etc.

  1. aura:valueInit – executes a logic when the component markup is initiated or loaded but the component page is not yet rendered. This is the first system event that gets fired.
  2. aura:valueRender – executes a logic when the component page is rendered completely or re-rendered
  3. aura:noAccess – executes a logic when the requested resource has no access permission
  4. aura:locationChange – executes a logic when the URL hash part has been changed
  5. aura:systemError – executes a logic when error occurs during the execution of server-side (apex controller) action.
  6. aura:valueChange – executes a logic when the aura attribute value is changed
  7. aura:valueDestroy – executes a logic when the component is destroyed and we want to do some custom cleanup during that period.
  8. aura:doneRendering - This event is automatically fired if no more components need to be rendered or rerendered due to any attribute value changes.Handle the aura:doneRendering event in a client-side controller. A component can have only one <aura:handler> tag to handle this event.
  9. <aura:handler event="aura:doneRendering" action="{!c.doneRendering}"/>

    For example, you want to customize the behavior of your app after it’s finished rendering the first time but not after subsequent rerenderings. Create an attribute to determine if it’s the first rendering.

    <aura:component>
        <aura:handler event="aura:doneRendering" action="{!c.doneRendering}"/>
        <aura:attribute name="isDoneRendering" type="Boolean" default="false"/>
        <!-- Other component markup here -->
        <p>My component</p>
    </aura:component>

    This client-side controller checks that the aura:doneRendering event has been fired only once.

    ({
      doneRendering: function(cmp, event, helper) {
        if(!cmp.get("v.isDoneRendering")){
          cmp.set("v.isDoneRendering", true);
          //do something after component is first rendered
        }
      }
    })
  10. aura:doneWaiting - 



<aura:handler event="aura:waiting" action="{!c.waiting}"/>
<aura:handler event="aura:doneWaiting" action="{!c.doneWaiting}"/>
<aura:attribute name="HideSpinner" type="Boolean" default="true"/>
<aura:renderIf isTrue="{!v.HideSpinner}">
  <div class="slds-spinner_container">
    <div class="slds-spinner--brand slds-spinner slds-spinner--large" role="alert">
      <span class="slds-assistive-text">Loading, Please Wait...</span>
      <div class="slds-spinner__dot-a"></div>
      <div class="slds-spinner__dot-b"></div>
    </div>
  </div>
</aura:renderIf>

Component JS Code
waiting: function(component, event, helper) {
  component.set("v.HideSpinner", true);
 },
 doneWaiting: function(component, event, helper) {
  component.set("v.HideSpinner", false);
 }


Happy Sharing...

No comments:

Post a Comment