Parent Child Component Communication in Angular

July 24, 2017
by Rahil Shaikh
  • Component interaction in Angular 2

Angular apps are built as a hierarchy of components. When you build applications you will need to communicate between components, while services are a good way to share data between components, there are specific methods to carry out parent-child component communication.

This tutorial will help us understand how we can share data between two sibling components in Angular 4 and also the component interaction between two components.

Throughout the article, the word Angular refers to Angular 2 and above unless mentioned specifically otherwise. This tutorial uses Angular 4.

In this article, we will learn to do…

  • Parent to child communication between components
  • Child to Parent communication between components

Component communication is something which you will be required to implement even in the simplest of Angular Application. When it comes to passing data from parent to child component we use property binding. In this case, we send the data from the parent component to the child component using an attribute. This attribute can then be accessed within the child component using the @input decorator.

Whereas in the case of a child to parent communication we capture the change in data due to any event or async operations within the child component. This event is then propagated to the parent component using the @Output decorator and Eventemitter.

We will see how this can be done in a real Angular Application in just about a moment.

If you are following Ciphertrick since past few months, you already know we have been building our crazy-quotes application. For this tutorial, I’ll build a feature that will display as users favorite quotes. While doing so, we will learn about component communication.

It’s great if you are following from our previous tutorial, but it’s equally great if you are here only for this tutorial.

Catching up

For people who are following along, we have built an app that will display the quote of the day for us. Now we will be adding a section that will display a list of static favorite quotes.
We can get the updated code but checking out the repo as shown below.

git clone https://github.com/rahil471/crazy-quotes.git

git checkout reusable-services

We already have two components, the root component and the the-quote.component. What we will do now is add a child component which will be responsible for displaying a single favorite quote. Let’s name it quote-tile.component.

Create the child component.

ng g component the-quote/quote-title

Now, we will leave our child component at that for now, let’s get a bit of background work and come back.

We will add a method to TheQuoteService which will give us our favorite quotes. So our service looks like below.

src/app/the-quote/the-quote.service

import { Injectable } from [email protected]/core';
import { Http } from [email protected]/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/throw';

@Injectable()
export class TheQuoteService {

  constructor(private http: Http) { }

  getQuote(): Observable <any>{
    return this.http.get('http://quotes.rest/qod').map(response => response.json().contents)
    .catch((err: Response|any)=>{
      return Observable.throw(err.statusText);
    });
  }

  //new function
  getFavQuotes() {
    return [{
      id: 2,
      quote: "Truth is a virus, courage is contagious",
      by: "unknown"
    },{
      id:3,
      quote:"Do not go gentle into that good night, Old age should burn and rave at close of day; Rage, rage against the dying of the light",
      by: "Dylan Thomas"
    },{
      id:4,
      quote:"It is well enough that people of the nation do not understand our banking and monetary system, for if they did, I believe there would be a revolution before tomorrow morning.",
      by: "Henry Ford"
    }];
  }
}

Now, calling this method in our the-quote.component, to fetch out favourite quotes.

src/app/the-quote/the-quote.component

import { Component, OnInit } from [email protected]/core';
/** New imports below */

import { TheQuoteService } from './the-quote.service'; // import our service


@Component({
  selector: 'app-the-quote',
  templateUrl: './the-quote.component.html',
  styleUrls: ['./the-quote.component.css']
})
export class TheQuoteComponent implements OnInit {
  myQuote :myQuote = {
    quote: "",
    by: ""
  };
  favourites: Array<myQuote>;
  constructor( private thequoteservice: TheQuoteService) { //initialize
  }

  ngOnInit() {
    this.thequoteservice.getQuote().subscribe((data)=>{ //use methods in our service
      this.myQuote ={
        quote: data.quotes[0].quote,
        by: data.quotes[0].author
      }
    }, (err)=>{
      this.myQuote ={
        quote: err,
        by: err
      }
    });

    this.favourites = this.thequoteservice.getFavQuotes(); //get favoutite quotes
  }

}

//creating myQuote interface
interface myQuote {
  id?: number,
  quote: String,
  by: String
}

If you see, we have made a few changes to our component from the last tutorial, other than setting this.favourites we have also created an interface myQuote

Parent to Child Component communication in Angular

We have already got the data into the-quote.component, but we are yet to display it anywhere on the screen. We will be displaying each of our fav quote in a block quote. Now, this blockquote that will display a single quote will be our child component which we have already generated using the Angular CLI.

src/app/the-quote/quote-tile/quote-tile.component.ts

import { Component, OnInit, Input } from [email protected]/core';

@Component({
  selector: 'app-quote-tile',
  templateUrl: './quote-tile.component.html',
  styleUrls: ['./quote-tile.component.css']
})
export class QuoteTileComponent implements OnInit {
  @Input() quote; //This tells our component to treat quote as an input property from the parent compnent
  constructor() { }

  ngOnInit() {
  }
}

Note the @Input() decorator.This tells our component to treat quote as an input property from the parent component.

src/app/the-quote/quote-tile/quote-tile.component.html

<div class="column content">
  <blockquote>{{quote.quote}}</blockquote>
  <small>- {{quote.by}}</small>
</div>

Our child component is ready. Now we will use it’s selector in our parent component.

src/app/the-quote/the-quote.component.html

<section>
  <div class="container">
    <h1 class="title">Quote of The Day</h1>
    <div class="columns">
      <div class="column content">
        <blockquote>{{myQuote.quote}}</blockquote>
        <small>- {{myQuote.by}}</small>
      </div>
    </div>
  </div>
</section>
<hr>
<section>
  <div class="container">
    <h1 class="title">Favourites</h1>
    <div class="columns">
      <app-quote-tile *ngFor="let item of favourites" [quote]="item"></app-quote-tile>
    </div>
  </div>
</section>

Focus on the below line from the above template.

<app-quote-tile *ngFor="let item of favourites" [quote]="item"></app-quote-tile>

We are using ngFor to repeat through our favourites then we are passing the value of item to quote. This is how we do property binding in Angular.

Child to Parent Component communication in Angular

Now that we know how we can communicate from parent to child, let’s learn to do it another way around.
In this case, we need to take action in our parent component of some event within the child component. The event could be a user action on the application like a click or some asynchronous API call or a timeout etc.

To begin with, let’s add a click event to author name and add a function to be called on that event within the quotetile.component.ts

src/app/the-quote/quote-tile/quote-tile.component.html

<div class="column content">
  <blockquote>{{quote.quote}}</blockquote>
  <small (click)="showAuthor($event, quote.by)">- {{quote.by}}</small>
</div>

Then in the component.

src/app/the-quote/quote-tile/quote-tile.component.ts

....
..
 showAuthor(event, by){
    alert("clicked");
  }
...
....

All we are doing here is alerting that the author name is clicked.
When we run this and click on the author name on the browser we will get this alert.

Cool, so now we have our event in the child component working. What we now need to do is somehow, notify about this event to our parent component.

We can do this using the @output decorator in conjunction with the EventEmitter class.

So let’s make changes in our quote-tile.component.ts.

src/app/the-quote/quote-tile/quote-tile.component.ts

import { Component, OnInit, Input, Output, EventEmitter } from [email protected]/core'; //importing output and eventEmitter

@Component({
  selector: 'app-quote-tile',
  templateUrl: './quote-tile.component.html',
  styleUrls: ['./quote-tile.component.css']
})
export class QuoteTileComponent implements OnInit {
  @Input() quote;
  @Output()
  authorClick: EventEmitter<String> = new EventEmitter<String>(); //creating an output event
  constructor() { }

  ngOnInit() {
  }

  showAuthor(event, author){
    this.authorClick.emit(author); //emmiting the event.
  }

}

Here first, we are importing the required Output and EventEmitter from @angular/core. Then we are declaring an authorClick output event using the @Output decorator. Finally, on click of author in showAuthor we are emitting the event with author as the $event data.

Now we need to bind this event on the app-quote-tile selector with the parent component template.

src/app/the-quote/the-quote.component.html

.....
...
..
<div class="columns">
      <app-quote-tile *ngFor="let item of favourites" [quote]="item" (authorClick)="showAuthorFromParent($event)"></app-quote-tile>
    </div>
..
...
....

In Angular round brackets are used for event bindings. We are calling showAuthorFromParent($event) function within our parent component when authorClick event is emitted from the clild component.

All we are left to do now is define the showAuthorFromParent in our parent component.

src/app/the-quote/the-quote.component.ts

....
...
.
  showAuthorFromParent = function(author){
    alert(author);
  }
.
...
.....

Run the server and try clicking on the author names. The application should show the clicked name as an alert.

Conclusion

Thus we have learned how we can, communicate between components using the @Input and @Output decorators in Angular 4. We have kept it at the very basic level and tried to simplify the explanation as much as possible. You learn more as you will work with Angular.

Code

This code can be downloaded from this github repo and is checked into component-communication branch.

About

Engineer. Blogger. Thinker. Loves programming and working with emerging tech. We can also talk on Football, Gaming, World Politics, Monetary Systems.

Free PDF

Subscribe and get AngularJS Tips PDF. We never spam!
First Name:
Email:

2 comments

  1. |

    in the tutorial i think towards the beginning of the parent to child communication when we’re trying to update the ‘the-quote.component.ts’ instead of showing what you do in that file we can see the services file again (SRC/APP/THE-QUOTE/THE-QUOTE.SERVICE >> shows up twice)

    • |

      Ahh my bad, thanks for bringing it to my notice. Fixed it. 🙂

Leave a Comment