Lightning Component Rendering Lifecycle – How to use render.js file?

What is Document Object Modal(DOM)?
DOM is nothing but a programming API for HTML and XML documents. DOM is the logical structure(i.e., tree) of the documents.

Now question is, how can we update the DOM structure created by pre-defined  Lightning Component?
Yes, we can manage and update the pre-defined DOM Structure by Custom Rendering functionality provided by Lightning Component Framework in Salesforce.

Salesforce Lightning Component Framework has provided us four phases of Rendering.

render()afterRender()rerender()unrender()
To override the base render() function after component initialization.To update the DOM tree after inserted DOM elements by render() function.This is triggered due to anything change to the components. It is called by the framework when a component is being destroyed.
Need to call superRender() function.Need to call superAfterRender() function.Need to call superRerender() function.Need to call superUnrender() function.
It returns value (DOM or NULL).Generally, it does not return a value.Generally, it does not return a value.Generally, it does not return a value.
event is not supported as a function parameter.event is not supported as a function parameter.event is not supported as a function parameter.event is not supported as a function parameter.
anything needs to be changed during default rendering.If DML operation is needed during component initialization, put logic in afterRender() function instaed of writing in init() function.It is triggered if anything is changed to the components just like button disable after clicked the button to show some results.If any component is not displayed due to aura:if condition is not satisfied or component is not displayed conditionally, at that point unrender() function of this component will be fired.
render : function(component, helper) {
var ret = this.superRender();
// custom rendering logic here
return ret;
}
afterRender: function (component, helper) {
this.superAfterRender();
// interact with the latest DOM tree made by render() function
}
rerender : function(component, helper){
this.superRerender();
// custom rerendering logic here
}
unrender: function (component, helper) {
this.superUnrender();
// custom unrendering logic here
}

Diagram of Rendering Lifecycle 

We have to create three lightning components to learning this article.

  1. defaultLightningPanel
  2. showContacts [In this learning, we will not describe how to write “showContacts” component. You can write this Lightning Component using lightning:dataTable]
  3. renderingLifecycle

Below images depicts our assignments: [At the time of opening the table, User can see the Welcome message and when User will click on “Show My Contacts” button, user will see all the  contacts created by that user.]

 

 

 

Step 1:  Create a Lightning Component Bundle named “defaultLightningPanel“.

defaultLightningPanel.cmp | to show the default message in the contacts panel.

<aura:component>
         <aura:attribute name="displayMessage" type="String"/>
         <lightning:layout multiplerows="true" verticalalign="center">
              <lightning:layoutItem padding="around-small" size="12">
                <div class="slds-align_absolute-center">
                  <label class="slds-text-color_inverse">{!v.displayMessage}</label>
                </div>
              </lightning:layoutItem>
          </lightning:layout>
</aura:component>

Step 2: we need to focus on defaultLightningPanelRenderer.js file to understand unrender functionality.

defaultLightningPanelRenderer.js | when this component is destroyed, unrender() function will be invoked. Later we will discuss in detail.

({
	unrender : function(component, helper) {
        this.superUnrender();
        console.log("---entry in unrender---"); 
        component.set("v.displayMessage","My Contact(s)");
        
        
    },
})

Step 3: Create a Lightning Component named “showContacts” in where you can pass the logged in User’s Id and returns the list of Contacts with respect to User Id. [In this learning, we will not describe how to write “showContacts” component. You can write this Lightning Component using lightning:dataTable]

Step 4: Create a Lightning Component Bundle named “renderingLifecycle“.

renderingLifecycle.cmp | to show the Contacts Panel

<aura:component implements="flexipage:availableForAllPageTypes" controller="RenderingLifecycleController">

            <aura:attribute name="welcomeMsg" type="String" description="to store the Welcome Message"/>
            <aura:attribute name="userName" type="String" description="to store the name of the logged in user"/>
            <aura:attribute name="userId" type="String" description="to store the name of the logged in user"/>
            <aura:attribute name="headerLine" type="String" description="to show the header of Welcome Panel"/>
            <aura:attribute name="contactObj" type="Object" description="define the instance of Contact object"/>              
            <aura:attribute name="contactColumns" type="List" description="define the columns to visible in lightning dataTable"/>
            <aura:attribute name="showContacts" type="Boolean" description="to control the show contacts panel"/>
            <aura:attribute name="defaultMessage" type="String" default="NO CONTACT(S)" description="default message"/>

            <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

            <lightning:card title="">
               <aura:set attribute="title">
                    <lightning:icon iconName="standard:avatar" size="small"/>
                    <span style="font-size: 1rem" class="slds-m-left_small"> {!v.headerLine}</span>
               </aura:set>
               <aura:set attribute="actions">
                      <lightning:button label="Show My Contacts" onclick="{!c.showMyContacts}"
                                        aura:id="showContactsBtnId"/>
               </aura:set>
               <aura:if isTrue="{!v.showContacts}">
                   <div style="padding:0.5rem;background: rgb(22, 50, 92);">
                        <label class="slds-text-color_inverse">{!v.defaultMessage}</label>
                   </div>
                   <c:showContacts userId="{!v.userId}"/>
                   <aura:set attribute="else">
                        <c:defaultLightningPanel displayMessage="{!v.defaultMessage}"/>
                   </aura:set>
                </aura:if>
             </lightning:card>
</aura:component>

Step 5: Update the controller.js file.

renderingLifecycleController.js |  doInit() function is invoked ans set the value of welcomeMsg attribute as “Welcome”.

When you will press “Show My Contacts” button, we have set the Boolean variable as “showContacts” as true to open the Contacts Panel with Contact records.

({
	doInit : function(component, event, helper) {
		console.log("---entry in init---");
                component.set("v.welcomeMsg", "Welcome ");
	},

	showMyContacts : function(component, event, helper){
               component.set("v.showContacts", true);
	}
})

Step 6: Update the helper.js file

renderingLifeCycleHelper.js | to show the contact records with respect to logged in User Id

({
	performShowingLoggedInUserDetails : function(component) {

		var action = component.get("c.getloggedinuserDetails");
		this.setShowingLoggedInUserDetails(component, action);
		$A.enqueueAction(action);
	},

	setShowingLoggedInUserDetails : function(component, action){

		action.setCallback(this, function(response){
			this.handleShowingLoggedInUserDetails(component, response);
		});
	},

	handleShowingLoggedInUserDetails : function(component, response){

		var responseState = response.getState();
		var responseError = response.getError();
		var responseValue = response.getReturnValue();

		switch(responseState){

			default: break;
			case 'NEW': break;
			case 'RUNNING': break;

			case 'SUCCESS':
					if(typeof responseValue != undefined &amp;amp;&amp;amp; responseValue.length &amp;gt; 0){
						component.set("v.userId", responseValue[0].Id);
						component.set("v.userName", responseValue[0].Name);
					}

					component.set ("v.headerLine", component.get("v.welcomeMsg") + component.get("v.userName"));

			case 'INCOMPLETE': break;
			case 'ERROR': 
				console.log('Response Error--&amp;gt;'+JSON.stringify(responseError));
				break;

		}
		 
	},


	
})

Step 7: update the render.js file

renderingLifecycleRenderer.js 

render() function is  called after completion of doInit() function by component.  By doInit() function, “welcomeMsg” attribute has been set to “Welcome“, now by render() function we have appended the value of “welcomeMsg” attribute as “To“.So, final value of “welcomeMsg” attribute has been set to “Welcome To” after completion of render() function.

After execution of render() function, afterRender() function will be invoked and the respective helper function “performShowingLoggedInUserDetails()” will be called to execute the server action to fetch the logged in User Name and concatenate the string with User Name, just like “Welcome To Santanu Pal“.

So, whenever the value of “welcomeMsg” attribute has been changed, the rerender() function will be triggered. For learning purpose, we will disable the button when “Show My Contacts” button has been pressed. In this case, the button’s visibility is controlled by a Boolean variable named “showContacts”.

 

({
	render : function(component, helper) {
        console.log("---entry in render---");
    	var ret = this.superRender();
    	component.set("v.welcomeMsg",component.get("v.welcomeMsg")+"To ");
    	return ret;
	},

    afterRender : function(component, helper){
        console.log("---entry in afterRender---");
        this.superAfterRender();
        helper.performShowingLoggedInUserDetails(component);
    },

    rerender : function(component, helper){
        console.log("---entry in rerender---");        
        this.superRerender();
        if(component.get("v.showContacts")){
            var showContactcsBtnId = component.find("showContactsBtnId");
            showContactcsBtnId.set("v.disabled", true);
        }
    },

	
})

Step 8: Please call the “renderingLifecyle” component from Lightning Application.

Console Statements
As per the Rendering Lifecycle, if we want to print console.log, this log will be generated in such a way:

At the time of loading the Lightning Application

—entry in init—
—entry in render—
—entry in afterRender—
—entry in rerender—

The last rerender function() is called because at the time of running render() function, the value of “welcomeMsg” attribute has been changed.

After clicked “Show My Contacts” button.

—entry in rerender—
—entry in unrender—
—entry in rerender—

unrender() function of defaultLightningPanel component is invoked when this component is destroyed from “renderingLifeCycle” component. If you see this component this panel will be invoked when “showContacts” is false(by default nature). Now, when we clicked “Show My Contacts” button”, “showContacts” boolean variable has been set to true and the “defaultLightningPanel” Lightning Component is hidden/destroyed and “showContacts” component will be opened.  As “defaultLightningPanel” Lightning Component is hidden/destroyed, the unrender() function of this component will be trigerred.

52,730 total views, 3 views today

Lightning Component – Server Side Implementation in a Smart Way

For this training purpose, we are showing the contact records with respect to an account on the Account Lightning Record Page. We are using aura:iteration with html table for training purpose. Please use lightning base components such as lightning:dataTable in future.

Step 1: Create the Apex Class named “ShowContactsController”

ShowContactsController.apexc | To return all the associated Contact Records

/* @name: ShowContactsController 
   @description: return the Contact Records*/

public class ShowContactsController {
    
    @AuraEnabled
    public static List<Contact> getContactRecords(String accountId){
        
        List<Contact> contactList = [SELECT Id, Name, Account.Name, Owner.name, LastModifiedDate, CreatedBy.Name FROM Contact WHERE Account.Id =: accountId ORDER BY LastModifiedDate Desc];
        if(contactList <> NULL && contactList.size()>0)
        	return contactList;
        else
            return NULL;
    }

}
  • Lightning Components will understand only methods with @AuraEnabled annotation in Apex Class.
  • Apex Methods must be static and access specifier should be public or  global for Lightning Component’s communication.

Step 2:  Create a lightning component bundle named “showContacts”.

showContacts.cmp | to show the associated Contact Records [you can use lightning:dataTable]

<!-- @name: showContacts
 	 @description: to show the contact records with respect to Account-->

<aura:component implements="flexipage:availableforAllPageTypes,force:hasRecordId" controller="ShowContactsController">
    
    <aura:attribute name="contactList" type="List" description="contains Contact records"/>    
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    
    <table class="slds-table slds-table_fixed-layout slds-table_bordered">
        <thead>
            <tr class="slds-text-heading--label">                  
                <th scope="col" class="slds-cell-wrap" title="Name">
                    <div class="slds-truncate">Name</div>                      
                </th>
                <!--<th scope="col" class="slds-cell-wrap" title="Account Name">
                    <div class="slds-truncate">Account Name</div>                      
                </th>-->
                <th scope="col" class="slds-cell-wrap" title="Owner">
                    <div class="slds-truncate">Owner</div>                      
                </th>
                <th scope="col" class="slds-cell-wrap" title="Last Modified Date">
                    <div class="slds-truncate">Last Modified Date</div>                      
                </th>
                <th scope="col" class="slds-cell-wrap" title="Created By">
                    <div class="slds-truncate">Created By</div>                      
                </th>
            </tr>
        </thead> 
        <tbody>
            <aura:iteration items="{!v.contactList}" var="con">
                <tr>
                    <td class="slds-truncate" title="{!con.Name}">
                        <lightning:formattedText value="{!con.Name}"/>            
                    </td> 
                    <!--<td class="slds-truncate" title="{!con.Account.Name}">
                        <lightning:formattedText value="{!con.Account.Name}"/>            
                    </td>-->
                    <td class="slds-truncate" title="{!con.Owner.Name}">
                        <lightning:formattedText value="{!con.Owner.Name}"/>            
                    </td> 
                    <td class="slds-truncate" title="{!con.LastModifiedDate}">
                        <lightning:formattedDateTime value="{!con.LastModifiedDate}" year="2-digit" month="short" day="2-digit"/>            
                    </td> 
                    <td class="slds-truncate" title="{!con.CreatedBy.Name}">
                        <lightning:formattedText value="{!con.CreatedBy.Name}"/>            
                    </td> 
                </tr>
            </aura:iteration>
        </tbody>
    </table>   
</aura:component>

showContactsController.js | calling the helper function

/*controller.js*/
({
	doInit : function(component, event, helper) {
		helper.performShowingContacts(component, event);
	}
})

showContactsHelper.js | calling the Server Class and get the response from Server and set the respective return value

/*helper.js*/
({
    performShowingContacts : function(component) {
		var action = component.get("c.getContactRecords");
		this.setupPerformShowingContactsAction(component, action);
		$A.enqueueAction(action);
    },
    
    setupPerformShowingContactsAction : function(component, action) { 

		action.setParams({
			"accountId":component.get("v.recordId")
		});

		action.setCallback(this, function(response){
        	this.handlePerformShowingContactsResultsCallBack(component, response)
        });	
    },
    
    handlePerformShowingContactsResultsCallBack : function(component, response) {

		var responseState = response.getState();
		var responseError = response.getError();
		var responseValue = response.getReturnValue();

		switch(responseState){

			default: break;
			case 'NEW': break;
			case 'RUNNING': break;

			case 'SUCCESS':
                
                if(!$A.util.isEmpty(responseValue))
                    component.set("v.contactList", responseValue);
                
                break;
                
            case 'INCOMPLETE': break;
			case 'ERROR': 
				console.log('Response Error-->'+JSON.stringify(responseError));
				break;
        }
        
    }
    
    
})


performShowingContacts:
This is responsible to call the specific method of Apex Class [Method Name: getContactRecords,  Class: ShowContactsController].
You can notice that we are calling the method by this syntax:  component.get(“c.getContactRecords”); And, $A.enqueueAction(action) is responsible to add the Server Side Action to the processing queue. Before going to this, the respective method named “setupPerformShowingContactsAction” is called.

setupPerformShowingContactsAction: This method is responsible to set the parameters in the respective method of the Apex Class.

      • In Apex Class: public static List<Contact> getContactRecords(String accountId)
      • In Helper: action.setParams({ “accountId“:component.get(“v.recordId”) });   // component.get(“v.recordId”) will return the current Account Record Id.

handlePerformShowingContactsResultsCallBack: action.setCallback() sets a callback action that is invoked after completion of server side actions. In this, method you will get the response state, response value as well as response errors.

There will be 5 types of responses.

      1. NEW – The action is created, but there is no progress yet
      2. RUNNING – The action is in progress.
      3. SUCCESS – The Action has been executed successfully.
      4. ERROR – The Server returned the error to Lightning Component
      5. INCOMPLETE – Component has not received the response. The Server might be down or Client is in offline mode.

After executed successfully, we have set the responseValue to contactList into the component. After that, component will iterate the contact list and will show the contact records.

Step 3: Place this Lightning Component into the Account Record Page.

 

Notes

  1. Calling server-side actions from Lightning Component are not counted against your organization’s API limits. However, all the Governor Limits in the Apex Class retain.
  2. The request payload limit of action.setParams() is 4 MB yet. So, please check the feasibility of  parameters in your apex class and js files of a Lightning Component.
  3. Always try to put the unique name of client-side and server-side actions in a component. For example, if we will write the function with same name such as “getContactRecords” in controller.js, it will call the function “getContactRecords” in controller.js instead of Calling Method of a Apex Class. May be, for that you can get error as in “unexpected execution process in infinite loop“.

 

11,355 total views, 6 views today

Advanced Event Communication – Application Event Propagation

Event Propagation is a way of communication in your application. Following are the phases supported in event communication

1. Capture Phase: The event is captured from application root to the source component. [top to bottom].

2. Bubble Phase: The event is bubbled up from source component to the application root. [bottom to top]

 

Application Event has one more phase called “Default” phase

3. Default  Phase: It respects framework’s default handling behavior.

Source Component [Where event is triggered]button

Application RootWindow

confused? Let’s start to discuss in detail

 

 

Before going to discuss, we need to understand the basic ideas about the component creation.

  1. Declarative Component: A component which is referred from outermost component which is the owner of the Containment Hierarchy.
  2. Programmatic Component:  A Component is invoked from the component by $A.createComponent() in js file.
  3. Container: We will call the component as container where {!v.body} or Aura.Component[] attributes are declared, means containing other component, not referring other component.
  4. Owner of Containment Hierarchy: A component which will create or refer to other component, not containing other component by {!v.body} tag or Aura.Component[] facet attribute. A component owner is  the component to responsible for creation of other component.

Application Event – It propagates to every owner in the hierarchy.

Default: Default Phase: If components are disconnected and want to communicate between the components, you have to use the Application Event. At that point, event phase should be default phase.  All component will catch the application event in same time. In this case, we can not use the bubble phase or capture phase.

If the components are connected and if we use Application Event, then we can use Bubble or Capture phase.

Disconnected Components

 

Component 1, Component 2, Component 3 and Component 4 are disconnected. Component 4 has the button named “Check Default Phase” by which the Application Event is registered and transmitted. Due to default behavior of handling components or default phase, all components or receivers will catch the event at same time. You can check the Graphical View image.

Hence, the result would be

I am the Receiver 1
I am the Receiver 2
I am the Receiver 3

In this component structure, you can not use the event Bubble Phase or Capture Phase.

Connected Components with Application Event Bubble Phase

In this component structure, three types of phases are allowed such as Default Phase, Bubble Phase and Capture Phase, because now these components are connected.  Now, we will discuss about Bubble Phase.

To run the Bubble Phase you have to mention phase= “bubble” in aura:handler tag of Component 1, Component 2 as well as Component 3. Just like

  <aura:handler event="c:applicationEvent" action="{!c.checkResponse}" phase="bubble"/> 

Due to Bubble Phase, application event will propagate from bottom to top or from Source Component[button] to root component[Component 1]. Component 3 and Component 1 will catch the event as they are the owner of containment hierarchy. Component 2 is not the owner of Containment Hierarchy, so it will not be able to do cat ch the event as well as not able to print the message.

Hence, the result would be

I am the Grand Child Component
I am the Parent Component

Connected Components with Application Event Capture Phase

To run the Capture Phase you have to mention phase= “capture” in aura:handler tag of Component 1, Component 2 as well as Component 3. Just like

  <aura:handler event="c:applicationEvent" action="{!c.checkResponse}" phase="capture"/> 

Due to Capture Phase, application event will propagate from top to bottom or from root component[Component 1] to Source Component[button]. Component 1 and Component 3 will catch the event as they are the owner of containment hierarchy. Component 2 is not the owner of Containment Hierarchy, so it will not be able to do cat ch the event as well as not able to print the message.

Hence, the result would be

I am the Parent Component
I am the Grand Child Component

You can check the Component Event Propagation about detailing of Capture and Bubble Phase

Sample Code Snippet for Disconnected Components with Default Phase

component 1 [Receiver 1]

<aura:component>
 <aura:handler event="c:applicationEvent" action="{!c.checkResponse}"/>
</aura:component>

component 2 [Receiver 2] 

<aura:component>
 <aura:handler event="c:applicationEvent" action="{!c.checkResponse}"/>
</aura:component>

component 3 [Receiver 3]

<aura:component>
 <aura:handler event="c:applicationEvent" action="{!c.checkResponse}"/>
</aura:component>

component 4 [button is here] 

<aura:component>
 <aura:registerEvent name="applicationEvent" type="c:applicationEvent"/>
 <lightning: button label="Check Default Phase" action="{!c.fireEvent}"/>
</aura:component>

LearningLightning.app | All components will be run from this application

<aura:component>
  <c:component 1/>
  <c:component 2/>
  <c:component 3/>
  <c:component 4/>
</aura:component>

Component 1, Component 2, Component 3 and Component 4 are disconnected. Component 4 has the button named “Check Default Phase” by which the Application Event is registered and transmitted. Due to default behavior of handling components or default phase, all components or receivers will catch the event at same time.

Hence, the result would be

I am the Receiver 1
I am the Receiver 2
I am the Receiver 3

Asynchronous Code Execution: You can pause or resume the event by the respective methods event.pause() or event.resume() in js files. These tags are needed to take the decision based on user input and response from asynchronous code and for certain conditions, we have to pause the event and after satisfying the criteria, again we can resume the event. By this, we can manage the flow-control mechanism for asynchronous code.

Stop Event Propagation: You can stop the event propagation by the respective method event.stopPropagation().

Q. If you want to print all the messages from all the connected components, what will you do?

IncludeFacets in Container Component: If you want to catch the event through container component, you need to write the attribute as “includeFacets=true” in aura:handler tag of a container component. In our example, we have a container component as “Component 2”. If we will include the attribute as “includeFacets=true“, it will be able to handle the event and print the message.

component 2 [Child Component in the Connected Components]

<aura:component>
  <aura:handler name="componentEvent" event="c:componentEvent" action="{!c.checkResponse}" includeFacets="true"/>
     {!v.body}
</aura:component>

Results in Bubble Phase using “includeFacets=true”  in Component 2

I am the Grand Child Component
I am the Child Component
I am the Parent Component

Results in Capture Phase using “includeFacets=true”  in Component 2

I am the Parent Component
I am the Child Component
I am the Grand Child Component

Q. If you want to print all the messages from all the disconnected components, what will you do?

Nothing to do. By default, all the messages will be printed from all the disconnected components due to “Default” phase behavior inclusion of Application Event.

Best Practice: If components are connected, use Component Event instead of Application Event. If components are disconnected, you should use the Application Event.

                                                                                        Thank you for concentrating a long time  session

12,806 total views, 3 views today

Advanced Event Communication – Component Event Propagation

Event Propagation is a way of communication in your application.  Following are the phases supported in event communication

1. Capture Phase:  The event is captured from application root to the source component. [top to bottom].

2. Bubble Phase:  The event is bubbled up from source component to the application root. [bottom to top]

Source Component [Where event is triggered]button

Application Root – Window

 

 

 

 

 

 

Before going to discuss, we need to understand the basic ideas about the component creation.

  1. Declarative Component: A component which is referred from outermost component which is the owner of the Containment Hierarchy.
  2. Programmatic Component:  A Component is invoked from the component by $A.createComponent() in js file.
  3. Container: We will call the component as container where {!v.body} or Aura.Component[] attributes are declared, means containing other component, not referring other component.
  4. Owner of Containment Hierarchy: A component which will create or refer to other component, not containing other component by {!v.body} tag or Aura.Component[] facet attribute. A component owner is  the component to responsible for creation of other component.

Component Event – It propagates to every owner in the hierarchy.

Default: Bubble Phase : Event will be passed from bottom to top means from source component to application root.

Component 1 is calling Component 2 which contains Component 3 and Component 3 is calling Component 4 where only the button “Check Bubble Phase” resides.  When you will click the button in Component 4, component event is registered in component 4[Source Component] and due to bubble phase[bottom to top] at first Component 3 will catch the event after that Component 1 will catch the event. But, Component 2 will not be able to catch the event because Component 2 is the container component and it is not the owner of the containment hierarchy means it is not exactly calling component 3, it is containing Component 3 in its body and also it is not the outermost component. Only Component 1[Parent Component] and  Component 3[Grand Child Component] are the owner of containment hierarchy, so they will be able to catch the component event and print the message.

Sequence of Events [When you will click the button “Check Bubble Phase“]

  1. Component Event is registered in Component 4.  This event will pass from bottom to top, just like bubble.
  2. Component 3 prints the message through its handler. Component 3 is the owner of Containment Hierarchy.
  3. Component 2  has the handler of this event, but it is the container component and not the owner of Containment Hierarchy. So, It will not be able to catch the event.
  4. Component 1 is the parent component and outer most component as well as owner of the Containment Hierarchy. Hence, it prints the message through its handler.

Hence, the result would be

I am the Grand Child Component
I am the Parent Component

Sample Code Snippet for understanding

component 1 [Parent Component]

<aura:component>
  <aura:handler name="componentEvent" event="c:componentEvent" action="{!c.checkResponse}"/>
  <c:component 2>
     <c:component 3>
  </c:component 2>
</aura:component>

component 2 [Child Component] | here {!v.body} is defined to contain the component 3

<aura:component>
  <aura:handler name="componentEvent" event="c:componentEvent" action="{!c.checkResponse}"/>
  {!v.body}
</aura:component>

component 3 [Grand Child Component]

<aura:component>
  <aura:handler name="componentEvent" event="c:componentEvent" action="{!c.checkResponse}"/>
  <c:component 4/>
</aura:component>

component 4 [button is here] | register the component event

<aura:component>
  <aura:registerEvent name="componentEvent" type="c:componentEvent"/>
  <lightning: button label="Check Bubble Phase" action="{!c.fireEvent}"/>
</aura:component>

Respective handlers for Component 1, Component 2 and Component 3 are the same as Component Event handler syntax.

Capture Phase: Event will be captured from top to bottom means from application root to source component.

We will take the same component structure to describe the Capture Phase.

 

 

To run the Capture Phase you have to mention phase=”capture” in  aura:handler tag of Component 1, Component 2 as well as Component 3. Just like

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

When you will click the button in Component 4, component event is registered in component 4[Source Component] and due to capture phase[top to bottom] at first Component 1 will catch the event after that Component 3 will catch the event. But, Component 2 will not be able to catch the event because of the same reason as Component 2 is the container component and it is not the owner of the containment hierarchy.

Sequence of Events [When you will click the button “Check Capture Phase“]

  1. Component Event is registered in Component 4.  This event will be captured from top to bottom.
  2. Component 1 prints the message through its handler. Component 1 is the owner of Containment Hierarchy.
  3. Component 2  has the handler of this event, but it is the container component and not the owner of Containment Hierarchy. So, It will not be able to catch the event.
  4. Component 3 is also owner of the Containment Hierarchy and will call the Component 4 to show the button “Check Capture Phase”. Hence, it prints the message through its handler.

Hence, the result would be

I am the Parent Component
I am the Grand Child Component

Asynchronous Code Execution: You can pause or resume the event by the respective methods event.pause() or event.resume() in js files. These tags are needed to take the decision based on user input and response from asynchronous code and for certain conditions, we have to pause the event and after satisfying the criteria, again we can resume the event. By this, we can manage the flow-control mechanism for asynchronous code.

Stop Event Propagation: You can stop the event propagation by the respective method event.stopPropagation().

Q. If you want to print all the messages from all the components, what will you do?

IncludeFacets in Container Component: If you want to catch the event through container component, you need to write the attribute as “includeFacets=true” in aura:handler tag of a container component. In our example, we have a container component as “Component 2”. If we will include the attribute as “includeFacets=true“, it will be able to handle the event and print the message.

component 2 [Child Component]

<aura:component>
  <aura:handler name="componentEvent" event="c:componentEvent" action="{!c.checkResponse}" includeFacets="true"/>
  {!v.body}
</aura:component>

Results in Bubble Phase using “includeFacets=true”  in Component 2

I am the Grand Child Component
I am the Child Component
I am the Parent Component

Results in Capture Phase using “includeFacets=true”  in Component 2

I am the Parent Component
I am the Child Component
I am the Grand Child Component

                                                               Thank you for concentrating a long time  session

4,439 total views, 1 views today

Events Communication in Lightning

Lightning Events are used to communicate to direct Lightning Components or indirect Lightning Components in Lightning Framework.

Component Event: This type of event can be fired from a Component and on other side, the component in the same hierarchy will handle/receive the event. Both components are correlated or coupled or directly connected.

Application Event: This type of event can be fired from a component and other component will receive/handle the event in the application. But, the components are not in the hierarchy model as well as components are not correlated or indirectly connected. You can refer this as Publish-Subscribe model.

Component Event Communication Rules:

1. Create Component Event(.evt) and declare the specific attributes as per business.
2. Register the Event into the notifier component where this event will be fired/triggered.
3. Receive the Event into the handler component where the value of Event attributes will be passed.
4. Both Notifier and Handler Components are in the same component hierarchy.

Let’s start with Component Event

Step 1: Create a Component Event named “componentEvent“.

componentEvent.evt | defines the component event

<aura:event type="COMPONENT" description="Component Event template">
   <aura:attribute name="message" type="String"/>
</aura:event>

Step 2: Create a notifier component bundle “notifier” where Event will be registered and fired.

notifier.cmp | register the component event


<aura:component>
      <!-- register Event -->
      <aura:registerEvent name="componentEvent" type="c:componentEvent"/>
      

<div class="slds-align_absolute-center slds-m-top_large">
         <lightning:button variant="brand" label="Submit (in notifier)" value="Trigger Event" onclick=" {!c.fireEvent}"/>
      </div>


</aura:component>

notifierController.js  | fired the component event

({
	fireEvent : function(component, event, helper) {
	    var componentEvent = component.getEvent("componentEvent");
            componentEvent.setParams({
                "message":"Event: ComponentEvent is fired." 
            });
            componentEvent.fire();	
	}
})

Step 3: Create a handler component bundle “handler” where the value of Event attributes will be passed.

handler.cmp | handler function is called

<aura:component> 
 <aura:attribute name="notificationMsg" type="String"/>
 <aura:handler name="componentEvent" event="c:componentEvent" action="{!c.receivesEvent}"/>
 <c:notifier/> 
 

<div class="slds-align_absolute-center slds-m-top_medium">
    <b>{!v.notificationMsg}</b> 
 </div>


</aura:component>  

handlerController.js | receives the triggered event

({
	receivesEvent : function(component, event, helper) {
	     var message = event.getParam("message");
             component.set("v.notificationMsg", message +' (in handler)');
        }
})

Step 4: Calling the handler from Lightning App named “LearnLightning“.

LearnLightning.app | To call the handler component from this application

<aura:application extends="force:slds>
    <c:handler/>
</aura:application>

Step 5: Results

From handler component, we are calling notifier component. So, both notifier and handler are in the same hierarchy.
We are registering the event into notifier and getting the result from handler component.

  • Submit button in notifier component

  • After clicked on Submit button, handler component receives the message from notifier by Component Event.

Application Event Communication Rules:

1. Create Application Event(.evt) and declare the specific attributes as per business.
2. Register the Event into the transmitter component where this event will be transmitted.
3. Receive the Event into the receiver component where the value of Event attributes will be passed.
4. Both Transmitter and Receiver component are not in same component hierarchy.

 

Let’s start with Application Event

Step 1: Create a Application Event named “applicationEvent“.

applicationEvent.evt | defines Application Event

<aura:event type="APPLICATION" description="Application Event template">
 <aura:attribute name="message" type="String"/>
</aura:event>

Step 2: Create a transmitter component bundle “transmitter” where Event will be registered and transmitted.

transmitter.cmp | register the application event


<aura:component>
       <!-- register Event -->
       <aura:registerEvent name="applicationEvent" type="c:applicationEvent"/>
       

<div class="slds-align_absolute-center slds-m-top_large">
          <lightning:button variant="brand" label="Submit (in transmitter)" value="Transmit Event" onclick=" {!c.transmitEvent}"/>
       </div>


</aura:component>

transmitterController.js  | transmitted the component event

({
	transmitEvent: function(component, event, helper) {
		var applicationEvent = $A.get("e.c:applicationEvent");
                applicationEvent.setParams({
                   "message":"Event: Application Event is transmitted." 
                });
                applicationEvent.fire();	
	}
})

Step 3: Create a receiver component bundle “receiver” where the value of Event attributes will be passed.

receiver.cmp | handler function is called

<aura:component>
    <aura:attribute name="notificationMsg" type="String"/>
    <aura:handler event="c:applicationEvent" action="{!c.receivesEvent}"/>
    

<div class="slds-align_absolute-center slds-m-top_large">
       <lightning:card title="Receiver">
          <b>{!v.notificationMsg}</b>
       </lightning:card>
    </div>


</aura:component>

receiverController.js | receives the transmitted event

({
	receivesEvent : function(component, event, helper) {
	     var message = event.getParam("message");
             component.set("v.notificationMsg", message);
        }
})

Step 4: Calling both transmitter and receiver components from Lightning App named “LearnLightning“.

LearnLightning.app

<aura:application extends="force:slds">
    <c:transmitter/>
    
    <c:receiver/>
</aura:application>

Step 5: Results

We are calling both components such as “transmitter” and “receiver” from the application. Both transmitter and receiver are not in the same hierarchy and they are disconnected in the application.

  •  Submit button is in transmitter component.  Receiver component is waiting for transmitted message from transmitter.
  • After clicked on Submit button, application event is transmitted. Receiver component is always checking that any request is coming or not from transmitter. When application event is received,  Receiver prints the message transmitted from transmitter.

3,837 total views, 2 views today

What is bound{! } expression and unbound{# } expression?

Bound Expression: {!v.attributeName}: Anything has been changed to the attribute in the Child Component affects the respective attribute in the Parent Component and vice-versa.
Unbound Expression: {#v.attributeName}: Anything has been changed to the attribute in the Child Component doesn’t affect the respective attribute in the Parent Component and vice-versa.

Following diagram depicts the use case of Bound Expression and Unbound Expression.

got the image. no 🙁 … Not an issue. Let’s we will start to discuss and again come to the this diagram

Let’s Start

Using Bound Expression
Step 1:Create a Child Component Bundle named “ChildComponent”

ChildComponent.cmp

<aura:component>
    <aura:attribute name="childAttr" type="String" description="defines child attribute"/>
    
<div class="slds-m-left--large">
          <b>In Child Component: </b>{!v.childAttr}     
          <lightning:button variant="brand" label="Change" onclick="{!c.changeChildAttr}" class="slds-m-left--small"/>
     </div>

</aura:component>

ChildComponentController.js | This method(“changeChildAttr”) is responsible to update the value of childAttr when “Change” button will be clicked.

({
	changeChildAttr : function(component, event, helper) {
		component.set("v.childAttr", "from Child Component.")
	}
})

Step 2: Create a Parent Component Bundle named “ParentComponent”.

ParentComponent.cmp

<aura:component>
    <aura:attribute name="parentAttr" type="String" default="from Parent Component."/>
    
<div class="slds-m-top--large">
        
<div class="slds-align_absolute-center">
    		<b>In Parent Component: </b> {!v.parentAttr}
        </div>

        
<div class="slds-m-top--large slds-m-left--large slds-align_absolute-center">
        	<c:ChildComponent childAttr="{!v.parentAttr}"/>
        </div>

     </div>

</aura:component>

Please notice that we have used Bound Expression {!v.parentAttr} whose default value “from Parent Component” will be passed to Child Component.

Step 3: As discussed earlier, we need to create the Lightning App(“LearnLightning”) to show the Result.

LearnLightning.app

<aura:application extends="force:slds">
    <c:ParentComponent />
</aura:application>

Step 4: Results

Result 1: Just run the app. Parent Component will pass the default value as “from Parent Component” to Child Component. So, both Component will display the same value on screen as “from Parent Component”.

Result 2: Just run the app. Now, you can click “Change” button on Child Component.So, the value of “childAttr” has been changed to “from Child Component”. Due to Bound Expression, it will be affected to the value of “parentAttr” in Parent Component. So, both Component will display the same value on screen as “from Child Component”.

Using Unbound Expression
Step 1:Same Child Component Bundle named “ChildComponent”

ChildComponent.cmp

<aura:component>
    <aura:attribute name="childAttr" type="String"/>
    
<div class="slds-m-left--large">
          <b>In Child Component: </b>{!v.childAttr}     
          <lightning:button variant="brand" label="Change" onclick="{!c.changeChildAttr}" class="slds-m-left--small"/>
    </div>

</aura:component>

ChildComponentController.js | This method(“changeChildAttr”) is responsible to update the value of childAttr when “Change” button will be clicked.

({
	changeChildAttr : function(component, event, helper) {
		component.set("v.childAttr", "from Child Component.")
	}
})

Step 2: Same Parent Component Bundle named “ParentComponent”.

ParentComponent.cmp

<aura:component>
    <aura:attribute name="parentAttr" type="String" default="from Parent Component."/>
    
<div class="slds-m-top--large">
        
<div class="slds-align_absolute-center">
    		<b>In Parent Component: </b>{!v.parentAttr}
        </div>

        
<div class="slds-m-top--large slds-m-left--large slds-align_absolute-center">
        	<c:ChildComponent childAttr="{#v.parentAttr}"/>
        </div>

     </div>

</aura:component>

Please notice that we have used Unbound Expression {#v.parentAttr} whose default value “from Parent Component” will be passed to Child Component. But, there will be no reflection from Child Component.

Step 3: Same Lightning App(“LearnLightning”) to show the Result.

LearnLightning.app

<application extends="force:slds">
    <c:ParentComponent />
</aura:application>

Step 4: Results

Result 1: Just run the app. Parent Component will pass the default value as “from Parent Component” to Child Component. So, both Component will display the same value on screen as “from Parent Component”.
reflection

Result 2: Just run the app. Now, you can click “Change” button on Child Component.So, the value of “childAttr” has been changed to “from Child Component”. Due to Unbound Expression, it will not change the value of “parentAttr” in Parent Component. So, Parent Component will display the value as “from Parent Component” and Child Component will display the value as “from Child Component”.bound result

Difference between Bound Expression and Unbound Expression

 
Bound Expression Unbound Expression
Using this type of expression, any change to the attribute of Child Component affects the attribute of the Parent Component and Vice-Versa.  Using this type of expression, any change to the attribute of Child Component doesn’t affect the attribute of the Parent Component and Vice-Versa.
It is bi-directional. It is one time uni-directional.
It hampers performance due to bi-directional flow. Please check component before using this type of expression.  It doesn’t hamper the performance due to  one time uni-directional flow , means there is no reflection from Child Component to Parent Component and Vice-Versa.
 It is difficult to study debug-log errors.  It is easy to track.
 It is applicable for Component Initialization as well as Data Binding.  It is not applicable for Component Initialization as well as in any controller/helper methods. It is only applicable for Data Binding.

 

Now Please go back to the first diagram of this post. Thanks 🙂

4,739 total views, 2 views today

How to use Component Id?

Component Id: This defines an identifier of the elements of a particular component. There are two types of Component Ids such as Local Id & Global Id.

Local Id-> To retrieve a component in Javascript. It is defined in “aura:id” attribute.

       <lightning:menuItem label="Home" value="home" iconName="utility:table" aura:id="menuItemId"/> 

Local Id doesn’t need to be unique. You can get the component using this syntax component.find(“menuItemId”) in Javascript files.

       doInit: function(component,event,helper){
          var menuItem = component.find("menuItemId");
       } 

Results: menuItem returns the single component if “menuItemId” is unique in component. It returns array of components if “menuItemId” is defined multiple times in the same component.

Global Id-> This is unique id which is generated runtime unique-Id of component instance. This is unique during runtime means this is a dynamic unique id.

Now, we can start to see the difference between Local Id & Global Id.

Step 1: Create a Component to use the Local Id and Global Id.

<aura:component>
 <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
 
 <div class="slds slds-align_absolute-center" Id = "{!globalId + '_div'}"> 
 <lightning:button variant="brand" label="Submit" onclick="{!c.onSubmit}" aura:id="buttonId"/>
 </div>
</aura:component>

To define the global id at component level, you need to write this {!globalId}. Local Id you can define in aura:id attribute.

Step 2: Create a controller.js to check the Local Id and Global Id.

({
     doInit : function(component, event, helper) {
        console.log("Component Global Id--->"+component.getGlobalId());
     },
     
     onSubmit : function(component, event, helper) { 
        console.log("Component Local Id--->"+component.getLocalId());
        console.log("Button Local Id--->"+component.find("buttonId").getLocalId());
        console.log("Button Global Id--->"+component.find("buttonId").getGlobalId()); 
     }
})

To access the Global Id in Controller.js, you need to write component.getGlobalId().

Step 3: For testing purpose, you can refer this Lightning Component from Lightning App. The following results will appear from Chrome Console, when you run this newly created Lightning App and hit the “Submit” button.

1. Component Global Id has been generated during run time and it is 3:0.
2.You can get the Local Id of the Lightning Button which is the element of the Component. It returns “buttonId” which is defined in aura:id attribute.
3.Also, you can get the Global Id of the Lightning Button and it returns 6:0.
4.you can make the unique identifier at the element of the component level by adding prefix or suffix with {!globalId}. You can see that we have made unique identifier at element in this way “{!globalId + ‘_div’}”.
5. You can see the Global Id by doing Inspect Element from browser

 

Difference between Local Id and Global Id

Local Id Global Id
A Local Id may be unique, but it’s not required.Global Id is always to be unique during run time of a component.

It is used for
-> differentiation of multiple instances of thecomponents.
-> debugging.
Define the Local Id in aura:id tags in component level.
Example: aura:id=”buttonId”

buttonId is the Local Id of a button in the component.
Define the Global Id in Id tags by merge syntax {!globalId} in component level.
Example: Id = “{!globalId}”
It is used for Lightning Tag.It is used for HTML tag.
It’s defined by developer.It’s defined by system and auto-generated during run time.
Retrieve Local Id from JavaScript:

component.getLocalId()
component.find(“buttonId”).getLocalId()
event.getSource().getLocalId()
Retrieve Global Id from JavaScript:

component.getGlobalId()
component.find(“buttonId”).getGlobalId()
event.getSource().getGlobalId()

Retrieve the element from HTML /browser’s Console:
document.getElementById(“_div”)
You can not use expression in aura:id tags. But, you can use the expression in Id tags.
You can use same Local Id in multiple aura:id tags.You can differentiate the Global Id for different HTML tags by adding prefix or suffix with {!globalId}.
Example: Id = “{!globalId+’_div’}”

7,954 total views, 1 views today

Lightning Component – Attributes

Attributes are used to perform the input and output operation in the Lightning Component or App. Attributes are just like Variables in the Apex Class. Need to use <aura:attribute> tag to declare the attribute in the Lightning Component or App.

Definition of <aura:attribute> tag

How can we access the attribute value?
Using this expression {!v.attributeName} In this case, it would be {!v.message}.

v means (View) Value Provider (represents in View Layer) which assists to access related data.

Attribute Types

  1. Primitives Data Types: String, Integer, Decimal, Double, Long, Date, Date/Time,  Boolean
  2. Collection: Array, Set, List, Map
  3. sObjects: StandardObject, CustomObject__c
  4. Custom Apex Class
  5. Framework Types: Aura.component, Aura.Component[]

Let’s GO

Step 1: Using the Same Lightning Component “Welcome.cmp” and same CSS file “Welcome.css” (Please create, if it’s not there)

Welcome.cmp | Attribute Declaration

<aura:component >    
    <!-- attributes declaration -->
    <aura:attribute name="message" type="String" default="Hello" description="Used for showing the message in Lightning Component"/>  
    
     <div class="slds slds-m-top--x-large slds-align_absolute-center tagLine">
    	<!-- access the attribute -->
        {!v.message}
    </div>
    
</aura:component>

Welcome.css | Describes Styling

.THIS.tagLine {   
    font-size:30px;
    color:#0066CC;   
}

Step 2: Calling from Lightning App “LearningLightning.app” with message attribute

<aura:application extends="force:slds">
    <c:Welcome message="Welcome to Everyone !!"/>
</aura:application>

Step 3: Result

Welcome Message - attributes

Step 4: Calling from Lightning App “LearningLightning.App” without message attribute

<aura:application extends="force:slds">
    <c:Welcome/>
</aura:application>

Step 5: Result

It will show “Hello” as the default value of the “message” attribute(in Step 1) due to we have not passed the value of “message” attribute from the App to Component.

hello - attributes

3,689 total views, 5 views today

Build your first Lightning Component – Only View

How to build your first Lightning Component?
Only View, No Logic

Step 1: Create Lightning Component Bundle named “Welcome”
After creation, we will get four primary files such as

  • Welcome.cmp
  • Welcome.css
  • WelcomeController.js
  • WelcomeHelper.js

We need to update Welcome.cmp & Welcome.css file for now.

Welcome.cmp | Describes View Layout

<aura:component>   
   

<div class="slds slds-m-top--x-large slds-align_absolute-center tagLine">
    	Welcome to Everyone !!
   </div>


</aura:component>

Welcome.css | Describes Styling

.THIS.tagLine{   
    font-size:30px;
    color:#0066CC;
}

Step 2: Create Lightning App named “LearningLightning”

LearningLightning.app | To run this newly created Lightning Component

<aura:application extends="force:slds">
    <c:Welcome/>
</aura:application>

You can notice that we are using the tag extends=”force:slds” to run the Lightning Application using Lightning Styles.

Step 3: Result

Welcome to Everyone(first Lightning Component)

3,090 total views, 2 views today