Pass Data Between Components Using @Output, @Input And EventEmitter In Angular



In Angular, we can use any component inside another component. Here, the component, which is used inside other component is called child component and the main component is called parent component. Let’s say for example, I am creating two components, which are given below.

  1. products.component 
  2. sidebarfilter.component

I had created product.component to display all the available products and sidebarfilter.component to provide the filter options to the user. In my case, I want to pass the searchterm/value, which is entered in an input box of sidebarfilter.component to products.component and in other case, I want to pass some value from product.component to sidebarfilter.component.

In this tutorial, I will show “how components can communicate with each other”, using @input,@output and EventEmittter.

There are certain ways from which components can communicate with each other.

  • @Input
  • @Output
  • Services

I will show, how it can be done, using @Input,@Output and Event Emitter.

Backend

Script file for the database 

  1. [code language=”sql”]  
  2. CREATE TABLE IF NOT EXISTS `product_tbl` (  
  3.   `p_id` int(11) NOT NULL AUTO_INCREMENT,  
  4.   `pname` varchar(500) NOT NULL,  
  5.   `pprice` double DEFAULT NULL,  
  6.   `pimg` varchar(1000) DEFAULT NULL,  
  7.   `soh` int(11) NOT NULL,  
  8.   PRIMARY KEY (`p_id`)  
  9. ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;  
  10.   
  11. --  
  12. -- Dumping data for table `product_tbl`  
  13. --  
  14.   
  15. INSERT INTO `product_tbl` (`p_id`, `pname`, `pprice`, `pimg`, `soh`) VALUES  
  16. (1, 'omega', 100000, 'http://cdn2.jomashop.com/media/catalog/product/o/m/omega-seamaster-planet-ocean-black-dial-men_s-watch-232.30.42.21.01.001_1.jpg', 5),  
  17. (2, 'timex', 2000, 'http://ecx.images-amazon.com/images/I/51Ezfl22mYL._AC_UL260_SR200,260_.jpg', 10),  
  18. (3, 'titan', 12000, 'http://ecx.images-amazon.com/images/I/51fnWFY3s3L._AC_UL260_SR200,260_.jpg', 15),  
  19. (4, 'fossil', 18000, 'http://i.ebayimg.com/00/s/NjAwWDYwMA==/z/ZN8AAOSwd4tT5KNF/$_32.JPG', 8),  
  20. (5, 'rolex', 125000, 'http://dvciknd2kslsk.cloudfront.net/images/watchfinderimages/Watch/Rolex/GMT-Master-II/76399-2005568029.jpg', 3);  
  21. [/code]   

I had created backend, using node.js, which can be downloaded here. Don’t forget to run NPM install to download all the dependencies from the package.json.

Keep in mind before fetching the data in Angular, your back-end Server must be on ( i.e. your Node. js Application should be on). To run node.js Application, navigate to the directory and write NPM start.

The table is created, using script file, back-end project, which is downloaded from GitHub link, so it is all set to start with fetching the data in Angular.

Frontend

I am using Angular-cli to generate the project. To start with first, I had created one class to store the products. This product class contains the fields given below. 

  1. [code language=”typescript”]  
  2. export class Product {  
  3.     public constructor(public p_id:number,public pname:string,public pprice:number,public pimg:string,public soh:number){  
  4.     }  
  5. }  
  6. [/code]   

After creating the class, I will require a Service, which will fetch the data from our back-end. 

  1. [code language=”typescript”]  
  2. import { Injectable } from '@angular/core';  
  3. import { Http,Response } from '@angular/http';  
  4. import 'rxjs/Rx';  
  5. @Injectable()  
  6. export class ProductdataService {  
  7. url:string="http://localhost:3000/products/";  
  8.   constructor(private _http:Http) { }  
  9.   
  10.   getAllProduct(){  
  11.     return this._http.get(this.url)  
  12.     .map((res:Response)=>res.json());  
  13.   }  
  14. }  
  15. [/code]   

In the Service, I had imported HTTP and respone from @angular/http and also imported rxjs/Rx for observables. I had created one variable and named it as a URL, which will store the URL of the backend. I had created one method getAllProduct, which is using GET method of http in fetching the data from the database. Now, as Services are injectable, I can call getAllProduct from any component, which is injecting this Service.

Simply, I want to display allProducts, so I am creating a component names as products.component.

products.component.html 

  1. [code language=”html”]  
  2.   <h1>Products</h1>  
  3.       <div class="row">  
  4.         <div *ngFor="let item of allProduct"  class="col-sm-6 col-md-4">  
  5.           <div  class="thumbnail">  
  6.             <img height="250" src="{{item.pimg}}" alt="...">  
  7.             <div class="caption">  
  8.               <h3>{{item.pname}}</h3>  
  9.               <p>{{item.pprice | currency:'INR':true }}</p>  
  10.               <p><a class="btn btn-primary" role="button">{{item.soh}}</a> <a class="btn btn-default" role="button">Button</a></p>  
  11.             </div>  
  12.           </div>  
  13.         </div>  
  14.       </div>  
  15. [/code]   

products.component.ts

  1. [code language=”typescript”]  
  2. import { Component, OnInit } from '@angular/core';  
  3. import { Product } from './product';  
  4. import { ProductdataService } from '../shared/productdata.service';  
  5. @Component({  
  6.   selector: 'app-products',  
  7.   templateUrl: './products.component.html',  
  8.   styleUrls: ['./products.component.css']  
  9. })  
  10. export class ProductsComponent implements OnInit {  
  11. allProduct:Product[]=[];  
  12.   constructor(private _data:ProductdataService) { }  
  13.   ngOnInit() {  
  14.     this._data.getAllProduct().subscribe(  
  15.       (data:Product[])=>{  
  16.         this.allProduct=data;  
  17.       }  
  18.     );  
  19.   }  
  20. }  
  21. [/code]   

Here, in the code given above, I am injecting the service and importing class which was created previously then on ngOninit method I am calling getAllProduct method and on subscribe method, I am fetching all the products in allProduct array and on HTML, I loop through the allProduct array to display all the products.


It is simple. Isn’t it? Now, I want to create one more component and named it as sidebarfilter.component, which I will used inside products.component, as shown below.


Now, I want to communicate between these two components i.e. sidebarfilter.component and products.component.

It means I want to pass the name of the category from products.component è sidebarfilter.component and value of the inputbox of sidebarfilter.component è products.component, as shown above.

  • Passing the value from products.component component

It can be done simply by declaring the result variable, as shown below. 

  1. @Input() result:string="";  
  2. @Input can be imported from @angular/core   

By declaring the variable as @Input, we can set it’s value from any other component, as shown below. 

  1. <app-sidebarfilter [result]=value ></app-sidebarfilter>   

It should be written on products.component.html

  • Passing the value from sidebarfilter.component component.

In this case, I want to pass the value of the inputbox to products.component on click of Search button, so I am creating custom event and emitting that event, using EventEmitter .

We can create custom event, which can be called from other component with the help of @output and EventEmitter and both can imported from @angular/core.

  1. @Output() clicked=new EventEmitter<string>();  

Here, the full source code of sidebarfilter.component is given below.

Sidebarfilter.component.html 

  1. [code language=”html”]  
  2. <div class="row">  
  3.   <h1>{{result}}  Search</h1>  
  4.  <div class="input-group input-group-lg">  
  5.   <span class="input-group-addon glyphicon glyphicon-search" id="sizing-addon1"></span>  
  6.   <input #input1 type="text" class="form-control" placeholder="Search Product Name" aria-describedby="sizing-addon1">  
  7. </div>  
  8. <br>  
  9. <button (click)="onClick(input1.value)" type="button" class="btn btn-primary">Search</button>  
  10. </div>  
  11. [/code]   

Sidebarfilter.component.ts

  1. [code language=”typescript”]  
  2. import { Component, OnInit,Output,EventEmitter,Input } from '@angular/core';  
  3. @Component({  
  4.   selector: 'app-sidebarfilter',  
  5.   templateUrl: './sidebarfilter.component.html',  
  6.   styleUrls: ['./sidebarfilter.component.css']  
  7. })  
  8. export class SidebarfilterComponent implements OnInit {  
  9.   @Input() result:string="";  
  10.   @Output() clicked=new EventEmitter<string>();  
  11.   constructor() { }  
  12.   ngOnInit() {  
  13.   }  
  14. onClick(searchTerm:string){  
  15. this.clicked.emit(searchTerm);  
  16. }  
  17. }  
  18. [/code]   

In the component given above, I am passing the value of inputbox to onClick method on (click) event with the help of template binding (#input1) and onClick method, it will emit my custom event clicked and pass the value to products.component.ts and also I am displaying the {{result}} in h1 tag, which can be set to products.component.

products.component.html 

  1. [code language=”html”]  
  2. <div class="container">  
  3.   <div class="row">  
  4.     <div class="col-md-3">  
  5.       <app-sidebarfilter [result]=value (clicked)="onClicked($event)"></app-sidebarfilter>  
  6.     </div>  
  7.     <div class="col-md-9">  
  8.       <h1>Products</h1>  
  9.       <div class="row">  
  10.         <div *ngFor="let item of allProduct" class="col-sm-6 col-md-4">  
  11.           <div class="thumbnail">  
  12.             <img height="250" src="{{item.pimg}}" alt="...">  
  13.             <div class="caption">  
  14.               <h3>{{item.pname}}</h3>  
  15.               <p>{{item.pprice | currency:'INR':true }}</p>  
  16.               <p><a class="btn btn-primary" role="button">{{item.soh}}</a> <a class="btn btn-default" role="button">Button</a></p>  
  17.             </div>  
  18.           </div>  
  19.         </div>  
  20.       </div>  
  21.     </div>  
  22.   </div>  
  23. </div>  
  24. [/code]   

products.component.ts 

  1. [code language=”typescript”]  
  2. import { Component, OnInit } from '@angular/core';  
  3. import { Product } from './product';  
  4. import { ProductdataService } from '../shared/productdata.service';  
  5. @Component({  
  6.   selector: 'app-products',  
  7.   templateUrl: './products.component.html',  
  8.   styleUrls: ['./products.component.css']  
  9. })  
  10. export class ProductsComponent implements OnInit {  
  11.   value:string="Watch";  
  12. allProduct:Product[]=[];  
  13.   constructor(private _data:ProductdataService) { }  
  14.   ngOnInit() {  
  15.     this._data.getAllProduct().subscribe(  
  16.       (data:Product[])=>{  
  17.         this.allProduct=data;  
  18.       }  
  19.     );  
  20.   }  
  21. onClicked(value:string){  
  22. if(value!=''){  
  23. this.allProduct=this.allProduct.filter(res=>res.pname.startsWith(value));  
  24. }  
  25. else{  
  26.   this._data.getAllProduct().subscribe(  
  27.       (data:Product[])=>{  
  28.         this.allProduct=data;  
  29.       }  
  30.     );  
  31. }  
  32. }  
  33. }  
  34. [/code]   

In the code given above, I am using sidebarfilter.component, as shown below.

  1. <app-sidebarfilter [result]=value (clicked)="onClicked($event)"></app-sidebarfilter>  

I am passing the value to the result, which will be bound on sidebarfilter.component and I am also calling custom event of sidebarfiltercomponent clicked, which is not HTML's event from products.component and performs the filter operation, which is based on the value.


Conclusion

Source code

In this tutorial, I gave a demo of how the components can talk/communicate to each other, using @Input,@Output and EventEmitter.

I hope it will be helpful to you.

Thanks for reading.


Similar Articles