Tuesday, July 17, 2018

Salesforce Lightning Events Part 2 - Building Component Events


Now, we are going to see component event in action and for this, let's start by creating a Lightning App to calculate the total income out of all income records in the table. To make this app let's have a look at the code below:-

<!-- Lightning Application extending slds -->
<aura:application extends="force:slds">
        <!-- Calling the container component -->
    <c:LightningEventsCompContainer />
</aura:application>
You can see above that our application is extending the force:slds library so that we can use the Lightning Tags following slds styling and I have invoked a single component in this app whose name is - LightningEventsCompContainer. This is our main container component which will contain 1 or more components. We'll read about this below in the post but for now you only need to know that this component is calling another Lightning Component named - LightningEventsComp1 which we are going to discuss now:-

LightningEventsComp1.cmp - Lightning Component

Our Lightning Component will look like this:-


This lightning component consists of the below code:-

<!-- Source Lighntning Component -->
<aura:component>
    <!-- Attributes for lightning:datatable -->
    <aura:attribute name="incomes" type="Object"/>
    <aura:attribute name="mycolumns" type="List"/>
    <!-- Registering the Lightning Event -->
    <aura:registerEvent name="totalIncomeComponentEvent" type="c:LightningComponentEvent"></aura:registerEvent>
    <!-- Defining a handler for lightning event -->
    <aura:handler name="totalIncomeComponentEvent" event="c:LightningComponentEvent"  action="{!c.handleRegisteredComponentEvent}"></aura:handler>
    <!-- Defining init handler for lightning component -->
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <!-- Lightning card section begins -->
    <lightning:card title="SFDC Stop Income Calculator" iconName="standard:account">
        <!-- Lightning card actions -->
        <aura:set attribute="actions">
            <!-- Action to toggle display of income form -->
            <lightning:button label="Show/Hide Income Form" onclick="{!c.toggleIncomeForm}" />
        </aura:set>
        <!-- Body of Lightning card -->
        <p class="slds-p-horizontal_small">
            <!-- Income form to add new income record to the table -->
            <div aura:id="incomeForm" class="hide">
                <lightning:Input aura:id="source" name="source" required="true" label="Income source"></lightning:Input>
                <lightning:Input aura:id="amount" name="amount" required="true"  label="Amount"></lightning:Input>
                <br />
                <lightning:button name="addIncome" label="Add Income" onclick="{!c.addIncome}"  variant="brand" ></lightning:button>
            </div>
            <br />
            <!-- Lightning datatable used to show income records -->
            <lightning:datatable data="{! v.incomes }" 
                columns="{! v.mycolumns }" 
                keyField="sno"
            />
            <br />
            <!-- Button used to fire the event that will pass total income to the application root -->
            <lightning:button name="addIncome" label="Calculate Total Income" onclick="{!c.fireTotalIncomeComponentEvent}"  variant="brand" ></lightning:button>
        </p>
    </lightning:card>
</aura:component>
As you can see in the above code, I have created two attributes, first attribute has the name income and is of type Object whereas the second attribute has the name mycolumns and is of type List. In this tutorial am going to make a simple table which will consist of the income source and it's amount.

Registering the Event

I have used the aura:registerEvent tag. This tag is used to register a new event and the name of the event is given as totalIncomeComponentEvent, this name should be same wherever we are going to reference this event. For the type, we have to refer to the actual event file, so I  have given the type of event as c:LightningComponentEvent as I am going to create a file with this name to define the event.

Handling the Event

The next tag is aura:handler which is used to handle the event we defined above. It's name is same as the name given in the registerEvent tag, the event attribute will consists of the reference to actual event file which is c:LightningComponentEvent and finally, the action attribute consists of the handleRegisteredComponentEvent function which is defined in the Lightning Controller and will be called as the event is fired. The next tag consists of the init handler which as we know will call it's action function as the component is initialized.

For this component, I have made a lightning:card with a suitable header and standard account icon as you can see in the image too. This card consists of a single action button which is used to toggle Income Form visibility by calling the lightning controller function toggleIncomeForm. In the card body, we have an income form which is hidden initially so, it is associated with a class hide that we'll define in css file. The income form consists of 2 lightning:input fields and 1 lightning:button and below the Income Form, we have a lightning:datatable tag which is used to make a table of income entries and finally a button named Calculate Total Income which is used to fire event to calculate the total income.

The two fields in the income form, are used to enter the income source and amount respectively and the button in the income form with label Add Income is used to call the addIncome function in controller and will add the income specified in the form to our datatable. The Calculate Total Income button below the table is used to fire the event we have registered and this task is done by calling fireTotalIncomeComponentEvent function of lightning controller. Below is the small introduction to lightning:datatable if you already know about this, you can skip ahead to event part.

lightning:datatable 

As I have used lightning:datatable in my component, I want to give a brief introduction to that. lightning:datatable tag is used to make a table by providing the table data in the compatible format. It is designed to deal and show the data of any sObject and has a number of features we can use. As in this section we are not going to deal with any apex controller, so I am going to pass static data to this table and update it accordingly. As you can see, in the datatable tag, I have given 3 attributes:-
  1. data -  This should be of type object and consists of data that is to be displayed in the table. Each record consists of key value pairs in which key is the fieldName same as defined in columns of table and value is the value of that field for that particular record.
  2. columns -  This should be of type list and consists of all columns with label along with their type and fieldName attributes.
  3. keyField - This is a required attribute to render the table and also helps in making the performance better. It associates each row with a unique id.
So, that's all with the lightning component, before moving to the controller let's have a look at defining a lightning event.

LightningComponentEvent.evt - Lightning Event

A lightning event can be considered as an envelope of information that you can pass from one component to another. Let's have a look at the code below:-
<!-- Defining a component event in Salesforce Lightning -->
<aura:event type="COMPONENT">
        <!-- Defining the totalIncome attribute of event with type decimal -->
        <aura:attribute name="totalIncome" type="Decimal"></aura:attribute>
</aura:event>

So, as you can see above, I have used aura:event tag to define an event. Each event has a type attribute in which we have to specify that whether it's a component or application event. I have given the attribute value as COMPONENT as we are dealing with component events now. To keep it simple. I have used a single attribute in this event. It's name is totalIncome and it's type is Decimal. This means that this event can carry one decimal value with it and traverse through it's path between components.

So, we have defined our event. Let's move on to lightning controller now in which we'll fire this event and define handler for this event.

LightningEventsComp1Controller.js - Lightning Controller

Moving on to the controller, before discussing, let's have a look at the code below:-

({
        // Init handler used to initialize lightning:datatable
        doInit : function(component, event, helper) {
                // Defining the columns to be used in lightning:datatable
            component.set('v.mycolumns', [
            {label: 'SNo.', fieldName: 'sno', type: 'number'},
            {label: 'Name of Source', fieldName: 'source', type: 'text'},
            {label: 'Amount', fieldName: 'amount', type: 'number'}
        ]);
        // Setting the incomes object with initial data to be included in datatable
        // Note tht fieldName in columns above are used as key values while inserting records
        component.set('v.incomes', [{
                sno: 1,
                source: 'Regular Job',
                amount: 10000
        },
        {
                sno: 2,
                source: 'Part Time Job',
                amount: 2000
        }]);
        },
        
        // Function to handle Lightning Event fired from this component itself.
        handleRegisteredComponentEvent: function(component, event, helper) {
                alert('Event handler at source component that fired the event.');
        },

        // Function to toggle Income Form visibility
        toggleIncomeForm: function(component, event, helper) {
                // Getting the income form reference
                var incomeForm = component.find('incomeForm');
                // Toggling the class of incomeForm to show/hide the form
                $A.util.toggleClass(incomeForm, 'hide');
        },

        // Function to add new income in the existing table data
        addIncome: function(component, event, helper) {
                // Getting all the income records currently present
                var incomes = component.get('v.incomes');
                // Forming a new income record by taking values from the income form
                var newIncome = {
                        sno: incomes.length + 1,
                        source: component.find('source').get('v.value'),
                        amount: parseFloat(component.find('amount').get('v.value'))
                };
                // Check if the new income record has value in each field if yes, push it to the list of existing income records
                if(newIncome.source!='' && newIncome.amount!='' && newIncome.source!=null && newIncome.amount!=null)
                        incomes.push(newIncome);
                // Set the income table records attribute with the new value
                component.set('v.incomes', incomes);
                // Empty the fields in the income form
                component.find('source').set('v.value','');
                component.find('amount').set('v.value','');
        },

        // This method is used to fire the income lightning event
        fireTotalIncomeComponentEvent: function(component, event, helper) {
                // Getting all the income records from the list
                var incomes = component.get('v.incomes');
                var totalIncome = 0;
                // Calculating the total income by adding the amount of each income record
                for(var i=0;i<incomes.length;i++) {
                        totalIncome += incomes[i].amount;
                }
                /* Getting the event defined by using component.getEvent() and passing the
                same value as in the name attribute of registerEvent tag */
                var totalIncomeComponentEvent = component.getEvent('totalIncomeComponentEvent');
                // Setting the attribute of event using setParams()
                totalIncomeComponentEvent.setParams({
                        totalIncome: totalIncome
                });
                // Firing the event
                totalIncomeComponentEvent.fire();
        }
})
As you can see above, we have a total of 5 functions in our controller file. Let's discuss each function one by one:-

  1. doInit:- This function is called initially when the component is loaded. In our component, when it is initially loaded, our lightning:datatable is pre-filled with some data so here, I am going to define the columns and initial data which will be used by my table. To set columns, we need mainly 3 things, the label, the fieldName (each column is refered by fieldName while entering data) and the type (data type) for the column. This is really useful when we deal with real sObject data as we can directly specify the column data type according to the data type of field. So, if you remember, mycolumns attribute in our lightning component was of type list, So I have made an array of columns and that array is stored in the mycolumns attribute. Similar format is used for the incomes attribute, an array with initial data is passed so that this data is displayed when the table is initially loaded. Notice that in case of data, the fieldName act as key and the value is the actual value for that column in a particular row.
     
  2. handleRegisteredComponentEvent:- This function simply sets an alert - Event handler at the source component that fired the event. It is simply used to learn about the order in which the event handlers are called as in bubble phase this function will be called in the beginning as the source itself will handle the event first and then move forward whereas in the capture phase this function will be called at last as the event handling starts from root. This function is called when LightningComponentEvent is fired.
     
  3. toggleIncomeForm:- This function is mainly used to toggle the income form visibility. First we are getting the incomeForm div by it's aura:id and then we are toggling the hide class so that the form is hidden if it was previously visible and vice-versa. This function is called when we click on Show/Hide Income Form button in the lightning component.
     
  4. addIncome:- In this function, first of all we are getting the income records that are already present in the data table.Then we form the newIncome object that consists of the serial number incremented by 1 and the source and amount value is taken from the incomeForm. Finally, we push the newIncome to the existing incomes array if all the fields have value and we set the incomes attribute with the updated list in our lightning component and set the source and amount fields to blank in incomeForm.
     
  5. fireTotalIncomeComponentEvent:- This function is responsible for firing our LightningComponentEvent and is called when we click on the Calculate Total Income button. It gets the table data from component consisting of income records, iterate them and calculate the total income. Finally we get our event defined in LightningComponentEvent file by referring it by it's name i.e. totalIncomeComponentEvent we set the param totalIncome by using the setParams() function which take the attribute name defined in the event file and it's value. At the end, we fire this event by calling fire() function on the variable that is referring the event so that the event is fired can be handled by it's respective handlers.
Our Component event and controller is ready, but css related to this component is yet to be defined which will show/hide our incomeForm. So, let's define our css file.

LightningEventsComp1.css

.THIS {
}
/* Class used to toggle the income form display */
.THIS .hide {
        display: none;
}
You can see above, I have defined a hide class that consists of only a single statement i.e. display:none; as I am toggling this class in the incomeForm on click of Show/Hide Income Form button which is calling the toggleIncomeForm function of controller responsible for toggling this class in the incomeForm by default incomeForm is hidden when we open the page as this class is applied in code.

Now, we are done with our component. If you remember, I have invoked single component in my Lightning App named:- LightningEventsCompContainer. This is the wrapper component which will consists of our LightningEventsComp1 component and also other components in the upcoming posts. So, let's have a look at this simple parent component now.

LightningEventsCompContainer.cmp

<!-- Wrapper/Parent component called directly from the Lightning Application -->
<aura:component>
        <!-- Attribute to store total income coming through the event -->
        <aura:attribute name="totalIncome" type="decimal" default="0" ></aura:attribute>
        <!-- Handler defined to handle 'totalIncomeComponentEvent' name same as used in registerEvent tag -->
        <aura:handler name="totalIncomeComponentEvent" event="c:LightningComponentEvent"  action="{!c.handleTotalIncomeComponentEvent}"></aura:handler>
        Outer Component
        <!-- Inner component section with border -->
        <div class="innerComponent">
                Inner Component Section Begin
                <!-- Calling the source component -->
                <c:LightningEventsComp1 />
                Inner Component Section End
        </div>
        <!-- Section to show total income -->
        <span class="totalIncome">Total Income = {!v.totalIncome}</span>
</aura:component>
As you can see in the above code, I have defined an attribute named totalIncome which is of type decimal with default value as 0. This parent component will mainly handle the event fired by the child component and as we know that the event carry the total income, that value will be used by this parent component and component will set this value in this totalIncome attribute. So, to capture the event, I have defined a handler with the same name as given while registering the event i.e. totalIncomeComponentEvent. This handler is for LightningComponentEvent so I have given this in the event attribute and is calling handleTotalIncomeComponentEvent function which I'll define in the lightning controller of this parent component.

Then I have written a text named Outer Component to make sure that this is the outer component and called the LightningEventsComp1 component in a separate div with class innerComponent. I have called this component by using a tag :- <c:LightningEventsComp1 />. Finally, I have displayed the total income attribute value in a separate div with class totalIncome.

LightningEventsCompContainerController.js

Moving on to the controller for this component, let's have a look at the code below:-

({
        // Function to handle Lightning Event
        handleTotalIncomeComponentEvent : function(component, event, helper) {
                alert('Event handler at the parent component');
                // Getting the value of totalIncome attribute of event using event.getParam()
                var totalIncome = event.getParam('totalIncome');
                // Setting the totalIncome attribute of component with the event's totalIncome attribute value.
                component.set('v.totalIncome', totalIncome);
        }
})
As you can see, in the above code, I have only a single function named:- handleTotalIncomeComponentEvent which is called automatically by our event handler tag when the event is captured by this component. Now if you remember, out event consists of the total income as the sum of all income amounts present in the table in it's totalIncome attribute. So, as the event is received, first of all an alert is there saying Event handler at the parent component and then I get the value of event attribute using event.getParam('totalIncome'); as the attribute name is totalIncome in event and finally I set my totalIncome attribute present in the parent component so that the total income which is displayed in the lower div in parent component is updated.

Now, our whole code is ready except the css for parent component. So, let's have a look at the css file below:-

LightningEventsCompContainer.css

.THIS {
}
/* class for the totalIncome text size and padding */
.THIS.totalIncome {
        font-size: 1.5em; 
        padding-left: 1em;      }
/* Class to add border to inner/source component */
.THIS.innerComponent {
        border: 1px solid black;
}
As, you can see  that our css consists of only two classes, totalIncome -  to give a proper font-size and padding to the div where total income is displayed and innerComponent which is giving a border to the innerComponent div calling LightningEventsComp1 component.

This is our final application that we made:-

Salesforce Lightning Events Part 1 - Component Events Introduction



A component event is fired from the instance of a component. It can be handled either by the component who has fired this event or any other component in the hierarchy that receives the component event and has a handler defined to handle that component event.

Propagation of Component Event

There are mainly two phases in component event propagation :-
  1. Bubble Phase
  2. Capture Phase

Bubble Phase

In this phase, when an event is fired, it'll traverse up in the hierarchy and will end at the application root. In this phase, any component in the hierarchy in which we have defined a handler for that event can handle that event or even stop it from propagating further towards application root.
In this phase, the event traverses from source component to top by traversing the components in hierarchy and will stop finally at the application root. The source component who fired the event, can easily handle that event without any restrictions as the propagation starts from itself.

Component Event Propagation in Bubble Phase

Capture Phase

In this phase, when an event is fired, it'll move directly to the application root and then from the application root it will move through the path that ends at the component who fired this event. While traversing this path, any other component in which we have defined a handler for that event can handle that event and even stop that event from propagating further in the hierarchy.
In this phase, the event traverses directly from source component to top and then move towards bottom by traversing the components in hierarchy back to source component. The event cannot be handled by the source component which fired the event if it's propagation is stopped by any other component in the hierarchy while traversing down from application root to source component.
Component Event Propagation in Capture Phase

By default, the component events traverse in Bubble Phase.

Events in Salesforce Lightning - Introduction


What is an Event ? Generally an event is a thing that happens or takes place. When we talk about events in JavaScript, they are simply a thing that happen to HTML element. There can be various types of events when we talk about HTML. For example:-
  1. Web page loaded is an event
  2. Clicking of a button is an event
  3. Changing text in an input field is also an event

So, we can say that any kind of interaction that happen in a webpage either automatically or by human interaction is an event. Now talking about the Salesforce Events, basically there are 2 types of events in Salesforce:- 
  1. Component Events
  2. Application Events

Component Events

A component event is an event that is fired by a lightning component. A component event can either be handled by the component itself or it can be handled by any other component which is present in the hierarchy that receives the event.

Application Events

An application event is generally like a broadcast message. Like if you send a broadcast, then all the receivers that are configured to accept that broadcast message receive that message. Similarly, an application event is fired by a component and all the other components that have the handler defined to receive that event are notified when the event is fired. Application Events are not bound by any hierarchy or relationship.

Salesforce recommends to use component events whenever possible as they have a limited scope. Application Events are handled at the application level and can be used to communicate between different components that are not related to each other.

Usually, we deal with the events that are fired when the user interacts with the browser. Such events are known as browser events. There are another type of events that are called system events that automatically trigger during the component life cycle. If you remember the Salesforce Lightning Tutorial Series, in first video, we added an init handler in our lightning component as shown below:-

<aura:handler name="init" action="{!c.getContactsList}" value="{!this}" />
In the above code snippet, you can see that I made a handler which runs when the component is initialized and i.e why salesforce has defined it to give the name init and in the above case, it calls the getContactList function which is present in our lightning controller. As we wanted to fetch our contact list when the page is loaded in the previous tutorial, so we used an init handler to do the task. Such event which is fired automatically on component initialization is an example of system event.

sObject Convertor - A utility application to convert records from one sObject to another


What is sObject Convertor ?

Recently, SFDC Stop crossed 100 Subscribers on Youtube. Thank you everyone for supporting and encouraging me to do more for the community. As a gift to all, I have made a utility application - sObject Convertor using which you can convert records from one sObject to another. 


How can I install sObject Convertor ?

Follow these steps to install sObject Convertor application in your own salesforce org:- 
  • Go to the deployment section of the github repository and click on Deploy to Salesforce button which looks like this:-
  • You'll be taken up to the github salesforce deploy tool. Click on Login to Salesforce button on the top right corner.
  • The tool will ask for permissions, click allow.
  • After giving the permissions, you'll have a screen like this:- 
  • Click on deploy button in the top right corner and all the code will be deployed directly to your salesforce org.
  • Now, go to your org homepage or any detail page where you want to embed this app as a lightning component.
  • Click on the Settings (gear) icon and click on Edit Page.
  • Search for lightning component named SObjectConvertor in the left search box.
  • Drag and drop the SObjectConvertor lightning component to your page layout.
  • Click on save and click on assign as org default (if needed). Click on back button, left from the top right corner and you'll be back to your page with the lightning component embedded into it.

Instructions for using the application

  1. Choose the source object and the destination object.
  2. Search for the records of source object.
  3. Click on add record button as you search for each record to add the record in the list of records to be converted.
  4. To define the sobject mapping you have two options:-
    1. Create a new mapping:- In this case, you have to manually click add row for each field in which you have to map a field of source sObject to a field of destination sObject.
    2. Choose an existing mapping:- In this case, you can choose the previously saved mapping and the field mapping rows will be auto populated.
  5. If you have created a mapping, you can save that mapping by clicking on Save Mapping button and then giving the name of mapping in the dialog that appears. This mapping can then be used in future.
  6. Click on convert records button.

Your records will be converted and there are two different sections for success and failures. In the success section, you'll have the ids of the source and the destination sObject records. Whereas in the failure section, you'll have the id of the source sObject record with the particular error message due to which that record is not converted.