In Focus

Introduction To Event Binding And Nested Components In AngularJS

In this article, you will learn about event binding and nested components in AngularJS.

In our previous post, we elaborated on:

  1. What pipes are.
  2. How they help us to transform the values within template.
  3. How we can chain pipes.
  4. What are custom pipes & how to create them.

We are already familiar with how to create a component in Angular 2. In this post, we’ll try to dabble more on components & understand how to do event handling, how we can create nested components, and what are Component Life cycle Events/hooks.

Event Binding

We’ve already seen how to bind a property with an HTML element through Property Binding (where data from Component was bound to the HTML element); i.e. by enclosing the HTML element’s attribute inside the “[]” brackets &and assigning the value of the Component’s property to it. This is one way type of binding from Component to HTML element; however, we sometimes need the opposite way where some action on HTML element updates the component’s data. This is where Event Binding comes into picture.

Any event such as button clicked, key press etc. occurring on the UI, the component will listen to those event and will execute the handler for it. To bind events in Angular 2, we need to enclose the JavaScript event in “()” brackets or by using “on-” prefix to the event to tell Angular that the event is an Angular event. Unlike Angular1.x where we used to have separate Angular events using “ng-“ prefix, in Angular 2, “()” are used to denote Angular that the event is an Angular event & not plain JavaScript event. You can access the event object through $event which is passed by the Angular.

To demonstrate event binding, we’ll update our emp-list.component.html file to have a button, on click of which we’ll toggle the employee photo column.

Below is the snap of code change made to emp-list.component.html.


As you can see, we are doing property binding on “value” attribute of button element, by switching the text of the button to “Show Image” or “Hide Image” based on the value of “showImageColumn” property which is declared in our EmployeeListComponent class. Also, we’ve binded the Angular click event to toggleImageColumn() declared in EmployeeListComponent class. We’ve also added *ngIf= “showImageColumn” structural directive to the table head (i.e. th) HTML element as well as to the table data (i.e. td) HTML element.

Here is the updated snap for EmployeeListComponent class.


Try running the application and check if our latest feature of toggling the image column is working.


On clicking the button, the photo column toggles. The below snap shows the same.


Component Life Cycle Hooks

Every component has a life cycle which is managed by Angular right from the component initialization till it gets destroyed. Angular creates the component, renders it, creates & renders the child/nested components, check for any data bound property changes, and then finally, destroys it by removing the component from the HTML DOM.

Angular provides us with some life cycle hooks (in the form of interfaces) which can be used for performing a task, such as - for loading data from a back-end, we can use ngOnInit method which is responsible for carrying out any pre load initialization work. Similarly, in ngOnDestroy method, we can explicitly try to release any used resources.

For more information on component life cycle hook, please refer to this link.

For demonstrating this, we’ll try to update EmployeeListComponent class. In our class, we are loading the employees[] model data at the class level. Now, we’ll implement the OnInit interface and will load the employees[] array in the ngOnInit() method.

Here is the updated code for the same.


As you can see, we’ve imported the OnInit interface from @angular/core library and implemented on the EmployeeeListComponent class. Inside the class, we provided definition for the ngOnInit method and loaded our employees[] model data there.

Note

  1. We didn’t make use of constructor for performing the same task because constructors are used for initializing the variables to default value and not for making service calls. For now, our employees[] data is not coming from back-end but soon we’ll try to get our data from back-end service. Making service calls inside constructor is not a good practice.

  2. We can implement multiple life cycle hooks for a single component as per our need. For more information on component life cycle hooks, please refer this link.

After making the changes, try running the application. You’ll see the same output.

Creating Nested Components

We can nest components into each other. The main reason for nesting a component is re-usability. If the component is going to be used frequently throughout the application, it’s better to create a nested component rather than defining the same logic again and again. Nested component is simply referred as “Child Component”. Nesting a component simply means, using the “selector” name of one component inside another and registering the component with the module/sub module of the application. We can also pass the data to/from between parent component and child component. To demonstrate this, we would convert our “Appraisal Rating” value from numbers to “*”. Below are the steps for the same.

To start with, we’ll first create a shared folder inside our root folder whereby we can put our shared/nested components of the application. Inside the shared folder, I’ve added new TypeScript file named “ar-star.component.ts”. Below is the code snap for the same.


As you can see, we provided selector as ar-star i.e. wherever we want to use this component inside a parent component, we’ll be simply using <ar-star> tag in the parent component html file. Also, I’ve provided inline styles for the component using the “styles”[] property. You can pass multiple inline styles to it. However, the component decorator also provides the object property named “styleUrls” where you can specify the multiple external style sheet relative file paths.

Below is the code snap for “ar-star.component.html”.


To use this, we’ll modify our app.module.ts for registering this newly created component. Below is the code snippet for the same. 

  1. /** Importing the angular modules from namespace */  
  2. import {  
  3.     NgModule  
  4. } from '@angular/core';  
  5. import {  
  6.     FormsModule  
  7. } from '@angular/forms';  
  8. import {  
  9.     BrowserModule  
  10. } from '@angular/platform-browser';  
  11. /** Importing the AppComponent from the application's app folder */  
  12. import {  
  13.     AppComponent  
  14. } from './app.component';  
  15. import {  
  16.     EmployeeListComponent  
  17. } from './emp/emp-list.component';  
  18. import {  
  19.     EmployeeSearchPipe  
  20. } from './emp/emp-search.pipe';  
  21. import {  
  22.     ARStarComponent  
  23. } from './shared/ar-star.component';  
  24. @NgModule({  
  25.     imports: [BrowserModule, FormsModule], //other modules whose exported classes are needed by component templates declared in this module.  
  26.     declarations: [AppComponent, EmployeeListComponent, EmployeeSearchPipe, ARStarComponent], // the view classes that belong to this module. Angular has three kinds of view classes: components, directives, and pipes.  
  27.     bootstrap: [AppComponent] //the main application view, called the root component, that hosts all other app views. Only the root module should set this bootstrap property.  
  28. })  
  29. export class AppModule {}   

Inside our emp-list.component.html, we are using the newly created ar-star component for displaying the employee appraisal ratings. Below is the code snippet for the same.


Now, it’s the time for us to pass the data from parent component to child component. To do this, we must have a property in child component decorated with an @Input() decorator. Also, we’ll need to implement OnChange life cycle hook since we need to manipulate the starWidth variable value based on the input appraisalRating value.

Below is the updated code for the same.


Now that we’ve a property decorated with @Input, we can use this in our parent controller to pass the data. Below is the update made in emp-list.component.html file.

  1. <td class="centerAlign">  
  2.     <ar-star [appraisalRating]="emp.appraisalRating"></ar-star>  
  3. </td>   

In the above fragment, we are passing data through property binding. In our HTML, [appraisalRating] is the property of ARStarComponent class which is binded to emp.appraisalRating (which is property of EmpListComponent class).

Try running the code. You’ll see the below output.


So, we have successfully passed the data from parent component to the child component. However, we might also need to pass from child component to parent component. To achieve this scenario, Angular 2 has provided us with @Output decorator which is used for passing data in the form of events.

To create an event, Angular 2 provides us with EventEmitter class which is a generic class. The expected generic type will be the type of value which will be returned when the event occurs. For instance, if we create an object of EventEmitter class with <int> generic type, then the return value of the event will be of type int. If the instance type is of complex object, then the return value would be complex object. To define the user defined event, we simply mark the event with @Output decorator and of type EventEmitter<type>. For demonstrating this, we’ll try to print employee’s appraisal rating value on click of it.
 
Below is the updated code for the same.
 

Below is the updated code for ar-star.component.html.


We are done with passing the value in the form of event from the child component to parent component. Now, we need an event handler to handle the event on parent component. Below is the updated code for EmpListComponent class.


As you can see, I’ve defined eRating property & ratingClickedHandler method which set the value of eRating variable. Here is the updated emp-list.component.html file. 

  1. <td class="centerAlign">  
  2.     <ar-star [appraisalRating]="emp.appraisalRating" (ratingClicked)="ratingClickedHandler($event)"></ar-star>  
  3. </td>   

Note

  1. ratingClicked was the event defined on our child component
  2. ratingClickedHandler is the event handler defined in our parent component
  3. $event is the event object passed by Angular. It contains the changes/updated values

Try running the application and you’ll see the below output.


On click of appraisal rating, you’ll see the below output.


In our next post, we’ll continue further. Till that time, you can download the solution and test it locally at your end. I am uploading the solution file with this post; but I won’t be able to upload the node_modules folder because of heavy size. So, I request you to do npm install before you run the application, after downloading it.