Passing data between Angular 2 Components

In the last article,We understood how to highlight selected row in Angular 2, Where we saw the concept of component communication and We had an overview of inputs,outputs, and EventEmitter. In this article, We will be passing data between Angular 2 Components passing data Angular 2 Components with the help of  inputs,outputs, and EventEmitter.

By doing so, We will understand,

  1. How to use  inputs and @input decorator.
  2. How to use  outputs and @output decorator.
  3. What is EventEmitter and when to use it?

Setting up our Application

Let's use Angular CLI to setup our application. If you don't have Angular CLI installed on your machine run the below command to install it globally.
npm install -g angular-cli
After Angular CLI intallation,to create a new Angular project Run below command. This command will create all the necessary files, download all the required external dependencies and do all of the setup work for us.

 

ng new AppName

 

The application

Here, we will pass data from one component to another component and vice versa. Just like the previous article, We will divide our application into components. The first component will be parent component and the second component will be child component.

To create components in the Angular application is very easy with the help of Angular CLI. Below command is used to create a component,
ng generate component componentName

Run the below commands in order to achieve this,

  1. To create parentView component run : ng generate component parentView
  2. To create childView component  run : ng generate component childView

We will pass data between these two components with the help of Inputs, Outputs, and Event Emitter.

Before going further let's take a look at main.ts and index.html file where we have to use parentView component.

main.ts:

/*
* Passing data Angular 2 Components
* @author Shashank Tiwari 
*/

import { bootstrap } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';

import { environment } from './app/';

import { ParentViewComponent } from './app/parent-view/';



if (environment.production) {
  enableProdMode();
}

bootstrap(ParentViewComponent);

index.html

<!-- 
Passing data Angular 2 Components
@author Shashank Tiwari 
-->


<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Highlight selected Row in Angular 2</title>
  <base href="/">
  <link rel="stylesheet" href="vendor/bootstrap/dist/css/bootstrap.min.css">

  {{#unless environment.production}}
  <script src="/ember-cli-live-reload.js" type="text/javascript"></script>
  {{/unless}}
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-parent-view>Loading...</app-parent-view>
  
    {{#each scripts.polyfills}}
    <script src="{{.}}"></script>
    {{/each}}
    <script>
      System.import('system-config.js').then(function () {
        System.import('main');
      }).catch(console.error.bind(console));
    </script>
  
</body>
</html>

Passing data between Angular 2 Components Passing data Angular 2 Components

1. Sending data from ParentView into childView : inputs

Now we have included parentView component into our main.ts file and we have used <app-parent-view> the selector to render the parentView template.

From parentView component, we will send data to ChildView component.

To make this happen we will use Inputs and we will understand each and every aspect of it. Take a look at parent-view.component.ts file what we have there.

parent-view.component.ts:

/*
* Passing data Angular 2 Components
* @author Shashank Tiwari 
*/

import { Component,EventEmitter } from '@angular/core';

import { ChildViewComponent } from './../child-view/';

@Component({
  moduleId: module.id,
  selector: 'app-parent-view',
  directives: [ChildViewComponent],
  templateUrl: 'parent-view.component.html',
  styleUrls: ['parent-view.component.css']
})
export class ParentViewComponent {

    sampleData : string ="some parent Data";
    constructor(){}
}

Nothing much to see here,except directives property inside the @component decorator to use childView component.

Let's have a look at parent-view.component.html, how we are sending data to childView component.

parent-view.component.html:

<!-- 
Passing data Angular 2 Components
@author Shashank Tiwari 
-->

<div class="container parent-view">
    <div class="">

    	<h3>Parent Component</h3>

		<input type="text" class="form-control" value="{{ sampleData }}" [(ngModel)]='sampleData'>
            
		<hr>

		<div class="child-view">
			<app-child-view [parentData]="sampleData" >app-child-view</app-child-view>
		</div>


	</div>
</div>

As you can see the above code is comprehensible, except <app-child-view> selector due to this [parentData]="sampleData" term. What does [parentData]="sampleData" do?

Let's understand,

  1. sampleData is nothing but our data, that we want to send into childView component.
  2. parentData inside squareBrackets ( [ ] ) acts as a key, by using this key we can receive the sampleData inside out childView component.

2. Receiving data into childView Component

Now let's receive data into childView component using inputs. There are two ways to use inputs, either we can use @input decorator or  we can use inputs attribute inside @component decorator.Here we will see both the method one by one.

1. Using @input decorator :

In order use, @input decorator we first need to include Input from @angular/core library, as shown below.

import { Input } from '@angular/core';

Now let's use @input decorator, to receive data from parent controller, In order to do that we will use the key written inside squareBrackets ( [ ] ) in parent controller.

@Input('parentData') incomingData: string;

Above code does the exact same thing let's break it down,

  1. @Input('parentData') : Here we are receiving the parentData by using it as a key.
  2. incomingData : We can refer this incoming input by name,Here we are referring this data by naming it to incomingData. If I talk in a more technical word, I would say here we making a difference between the instance property (incomingData) and attribute key ( i.e. parentData).
  3. :string :  Type of this incoming input.

 

2. inputs attribute inside @component decorator:

Here we need not to include Input from @angular/core library, we can directly use inputs option inside @component decorator as shown below. Inputs attribute does the same thing.

After the explanation of  @input decorator I think I need not explain the below code, let me know if you have any doubts.

@Component({
    moduleId: module.id,
    -----
    -----
    inputs: ['parentData : incomingData'],
    -----
    -----
})

 

Let's see how we are receiving data into our childView component. In the below code we using @input decorator to receive data. Now we can use incomingData variable anywhere in our childView component.

child-view.component.ts :

/*
* Passing data Angular 2 Components
* @author Shashank Tiwari 
*/

import { Component,Input } from '@angular/core';

@Component({
  moduleId: module.id,
  selector: 'app-child-view',
  templateUrl: 'child-view.component.html',
  styleUrls: ['child-view.component.css'],
})

export class ChildViewComponent {

    @Input('parentData') incomingData: string;

    constructor() { }
}

 

In child-view.component.html, we can use incomingData variable as shown below.
child-view.component.html :

<!-- 
Creating Highlight selected row Angular 2 application
@author Shashank Tiwari 
-->


<h3>Child Component</h3>

<div class="parent-data">
    Data from parebt view : <b>{{ incomingData }}</b>
</div>

Sending data from childView to parentView : outputs

Here we will use outputs and EventEmitter, before digging into outputs let's first understand EventEmitter.

EventEmitter:

EventEmitter is class which is used to emit custom events. In more simple term, EventEmitter is an object which create observer pattern. In the below image object A is event emitter class which emits custom events and other objects can receive the event emitted by object A.

 Passing data Angular 2 Components EventEmitter Working

EventEmitter Working

EventEmitter maintains the list of subcriber objects which can receive the event emitted by the EventEmitter object  as explained above.

Outputs

With the help of EventEmitter, data is emitted from childView component and parentView component receives the emitted event. To practically implement this theory we will use outputs by attaching EventEmitter to it, here also we have two ways to use outputs .

Either we can use @output decorator or  we can use outputs attribute inside @component decorator.

1. @output decorator:

Open child-view.component.ts and add the below code. In the below code, we have to first import output and EventEmitter.

child-view.component.ts :

/*
* Passing data Angular 2 Components
* @author Shashank Tiwari 
*/

import { Component,Input,EventEmitter,Output } from '@angular/core';

@Component({
  moduleId: module.id,
  selector: 'app-child-view',
  templateUrl: 'child-view.component.html',
  styleUrls: ['child-view.component.css'],
})
export class ChildViewComponent {

    @Input('parentData') incomingData: string;

    @Output('childData') outgoingData = new EventEmitter<string>();

	childSampleData :string = "Some child Data";

	constructor() { }

	public sendData(data:any){
		this.outgoingData.emit(data);
	}
}

Explanation:
1. In the ChildViewComponent class, we have output decorator with EventEmitter attached to it.

  1. @Output('childData') : Here childData acts as a key,which is used to carry the data in the form of Events.
  2. outgoingData : This is an instance property or simply the name of the variable.
  3. = new EventEmitter() : By doing this we are attaching EventEmitter to it childData or more accurately @output decorator.

2. sendData() emits the data whenever this function executes.

 

2.outputs attribute inside @component decorator:

Using this technique we need not to import Output just like inputs. Let's write child-view.component.ts file with outputs attribute inside @component decorator.

child-view.component.ts:

/*
* Passing data Angular 2 Components
* @author Shashank Tiwari 
*/


import { Component,Input,EventEmitter } from '@angular/core';

@Component({
  moduleId: module.id,
  selector: 'app-child-view',
  templateUrl: 'child-view.component.html',
  styleUrls: ['child-view.component.css'],
  outputs: ['childData : outgoingData'],
})
export class ChildViewComponent {

    outgoingData = new EventEmitter<string>();

    childSampleData :string = "Some child Data";

	constructor() { }

	public sendData(data:any){
		this.outgoingData.emit(data);
	}
}

Explanation:
1. In the @component decorator , we have outputs property outputs: ['childData : outgoingData'] which specifies the key value pair.
2. Here, childData is acting as key and outgoingData is acting as value.

And, rest of the things are same.

But wait when do we call sendData() function ?

We call it from childView templates, whenever we intend to send data from childView component to parentView component.

In the below code, whenever any change occurs in ngModel we call sendData() function by using ngModelChange.
child-view.component.html :

<!-- 
Creating Highlight selected row Angular 2 application
@author Shashank Tiwari 
-->


<h3>Child Component</h3>

<div class="parent-data">
    Data from parebt view : <b>{{ incomingData }}</b>
</div>

<div class="child-data">
    <input type="text" class="form-control" 
		value="{{ childSampleData }}" 
		[(ngModel)]='childSampleData' 
		(ngModelChange)="sendData($event)" 
		placeholder="write some thing to send parent component">
</div>

Receiving event from childView into parentView

Lastly, we have to receive event emitted by childView component. Open the parent-view.component.html add the below code.
parent-view.component.html :

<!-- 
Creating Highlight selected row Angular 2 application
@author Shashank Tiwari 
-->


<div class="container parent-view">
    <div class="">

    	<h3>Parent Component</h3>

			<input type="text" class="form-control" value="{{ sampleData }}" [(ngModel)]='sampleData'>

			<br>

			<p>Data from child component : <b>{{ sampleChildData }}</b></p>
		<hr>

		<div class="child-view">
			<app-child-view [parentData]="sampleData" (childData)='handleEvent($event)'>app-child-view</app-child-view>
		</div>


	</div>
</div>

Notice that In the above code we have added (childData)='handleEvent($event)'.

2. The (parenthesis) handle outputs : (childData)='handleEvent($event)'
Explanation:

  1. childData is the name of the output that we want from the childView component.
  2. handleEvent() is a function that will be called whenever event will be emitted by childView component
  3. $event a variable used to carry output data.

Now let's check the parent-view.component.ts file what we have there. In the below code, we have added handleEvent() which updates the sampleChildData variable.

parent-view.component.ts:

/*
* Passing data Angular 2 Components
* @author Shashank Tiwari 
*/


import { Component,EventEmitter } from '@angular/core';

import { ChildViewComponent } from './../child-view/';

@Component({
  moduleId: module.id,
  selector: 'app-parent-view',
  directives: [ChildViewComponent],
  templateUrl: 'parent-view.component.html',
  styleUrls: ['parent-view.component.css']
})
export class ParentViewComponent {

    sampleData : string ="some parent Data";

    sampleChildData : string = '';

	constructor(){ }

	public handleEvent(childData:any){
		this.sampleChildData = childData;
	}
}

Final thoughts

So which technique you should use to send and receive data, decorators or input/output inside component decorator ?
Well, the answer is, it's completely up to you and you can use any of them. decorators or input/output inside component decorator both do the same thing.

For now, that's it.

If you like this article share with others and for more Angular 2  article stay tuned.

 

 

 

  • Ankur Vishwakarma

    Nice tutorial bhai >:)

  • Arun pandian

    Good explanation..Perfectly Working …

  • Alejandro Condori Cabrera

    Thanks!