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:-
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:-
<!-- Lightning Application extending slds --> <aura:application extends="force:slds"> <!-- Calling the container component --> <c:LightningEventsCompContainer /> </aura:application>
LightningEventsComp1.cmp - Lightning Component
Our Lightning Component will look like this:-
This lightning component consists of the below code:-
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.
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.
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>
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:-
- 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.
- columns - This should be of type list and consists of all columns with label along with their type and fieldName attributes.
- 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.
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.
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:-
As you can see above, we have a total of 5 functions in our controller file. Let's discuss each function one by one:-
({ // 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(); } })
- 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.
- 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.
- 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.
- 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.
- 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; }
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>
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); } })
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; }
This is our final application that we made:-
No comments:
Post a Comment