How do components communicate in Angular and how to use @Input and @Output annotations?

Photo by Alex Andrews on Pexels.com

There are five ways through which angular components can communicate with each other :

  1. Through @Input annotation
  2. Through @Output annotation
  3. Using local template reference.
  4. Using services
  5. Using @ViewChild annotation

Lets look at @Input and @Output annotation use cases in this post.

  1. @Input annotation

Say in one component you have a list of items.

You create one more component for holding details about each item.

You show the list of items in one screen and when user selects any of the item you show the second component with the details.

For the above use case the first component needs to pass the item to the second component .

This can be done through @Input annotation.

This annotation needs to be declared in the second (child) component.

A simpler example below:

Parent component :

The typescript component code :

import { Component, OnInit } from '@angular/core';
import { Child } from '../child';

@Component({
  selector: 'app-parent-for-input-example',
  templateUrl: './parent-for-input-example.component.html',
  styleUrls: ['./parent-for-input-example.component.css']
})
export class ParentForInputExampleComponent implements OnInit {


  children:Child[] = [];
  parent:any;
  constructor() { 

    this.parent = {


      children:[
  
        {"name":"Ram","age":"30","email":"ram@srilanka.com"},
        {"name":"Lakshmanan","age":"25","email":"lakshmanan@india.com"},
        {"name":"hanuman","age":"22","email":"hanuman@mountains.com"}
  
      ]
    }

  }

   
  
  ngOnInit() {

    console.log(this.parent);

    for(let ch of this.parent.children){

      var child:Child = new Child(ch.name,ch.age,ch.email);

      this.children.push(child);
    }

  }




}

The above component code just populates a list of children each with the fields name , age and email id. The model object ‘Child’ holds each child in the list.

The model code :

export class Child {

    name:string;
    age:string;
    email:string;


    constructor(name,age,email){


        this.name = name;

        this.age = age;

        this.email = email;
        
    }
}

The HTML template code :

<table *ngFor="let child of children">
<app-child-for-input-example  [child]="child" ></app-child-for-input-example>

</table>

In the above code , the list of children are iterated and each child is passed to the child component.

Here is the child component code :

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Child } from '../child';

@Component({
  selector: 'app-child-for-input-example',
  templateUrl: './child-for-input-example.component.html',
  styleUrls: ['./child-for-input-example.component.css']
})
export class ChildForInputExampleComponent implements OnInit {


  @Input()
  child:Child;

 
  constructor() { }

  ngOnInit() {
  }


}

Notice the @Input annotation declared on top of a reference to Child object. This will hold the object passed by the parent component.

Here is the template code of child:

<tr>

<td><label>Name: {{child.name}}</label></td>


<td><label>Age: {{child.age}}</label></td>

<td><label>Email :{{child.email}}</label></td>



</tr>

On running this app the below output is displayed :

Name: Ram	Age: 30	Email :ram@srilanka.com	
Name: Lakshmanan	Age: 25	Email :lakshmanan@india.com	
Name: hanuman	Age: 22	Email :hanuman@mountains.com	

2) Using @Output annotation

If the child component wants to communicate to the parent component that can be achieved through @Ouput annotation.

This annotation should also be included in the child component.

This is used to emit an event to the parent component.

For example in the above case , if a button is provided for each child and if the button is clicked the event can be passed to the parent component with any value from the child.

Here is the code:

Updated child typescript code :

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Child } from '../child';

@Component({
  selector: 'app-child-for-input-example',
  templateUrl: './child-for-input-example.component.html',
  styleUrls: ['./child-for-input-example.component.css']
})
export class ChildForInputExampleComponent implements OnInit {


  @Input()
  child:Child;

  @Output()
  wished = new EventEmitter();

  constructor() { }

  ngOnInit() {
  }

  sayHello(){

    this.wished.emit(this.child.name);
  }
}

The updated template code :

<tr>

<td><label>Name: {{child.name}}</label></td>


<td><label>Age: {{child.age}}</label></td>

<td><label>Email :{{child.email}}</label></td>


<td><button (click)="sayHello()">Say Hello</button></td>
</tr>

A button has been added and on click of it the method ‘sayHello()’ is invoked.

This method emits an event ‘wished’ with the child name as parameter.

Here is the updated parent code :

The template code :

<table *ngFor="let child of children">
<app-child-for-input-example  [child]="child" (wished)="displayGreeting($event)"></app-child-for-input-example>

</table>

The event ‘wished’ is included within the child component declaration and when it is fired the method ‘displayGreeting()’ is called from the parent component.

Here is the updated component code :

import { Component, OnInit } from '@angular/core';
import { Child } from '../child';

@Component({
  selector: 'app-parent-for-input-example',
  templateUrl: './parent-for-input-example.component.html',
  styleUrls: ['./parent-for-input-example.component.css']
})
export class ParentForInputExampleComponent implements OnInit {


  children:Child[] = [];
  parent:any;
  constructor() { 

    this.parent = {


      children:[
  
        {"name":"Ram","age":"30","email":"ram@srilanka.com"},
        {"name":"Lakshmanan","age":"25","email":"lakshmanan@india.com"},
        {"name":"hanuman","age":"22","email":"hanuman@mountains.com"}
  
      ]
    }

  }

   
  
  ngOnInit() {

    console.log(this.parent);

    for(let ch of this.parent.children){

      var child:Child = new Child(ch.name,ch.age,ch.email);

      this.children.push(child);
    }

  }


displayGreeting(name:String){


  alert(name+" says Hello");
}
  

}

Here, on click of the button ‘Say Hello’ the message Childname says Hello” is alerted to the user ,where Childname is the name of the child passed from the child component.

That’s it!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s