How to communicate between Angular components using @ViewChild annotation

In the previous post I showed how to communicate between two angular components using local template reference.

The drawback using that strategy is that you can’t reference the child component inside parent component’s typescript code. It can be referenced only inside the parent template.

This can be overcome by using @ViewChild annotation.

This will inject a child component instance inside a parent component . This instance can then be used to access child instance properties and methods.

Here is a child component which asks the parent “Who pinged me?”.

The parent component pokes the child to invoke this response and also accesses the name attribute of the child.

The child component code :

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

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

  constructor() { }

  ngOnInit() {
  }

  name;

  country = 'India';

  collectName(event: any) {

    this.name = event.target.value;

  }

  pingBack() {



    return "Who poked me?";
  }

}

The child component has two attributes “name” and “country” . “country” has a default value “India”.

“name” is populated by getting value from an input text box.

Here is the template code :

<br>


<label>Enter the child's name:</label>
<input  (keyup)="collectName($event)"/>

In the above template code , user is asked to enter a name which is stored in the “name” attribute of the component .

Here is the parent component code :

import { Component, OnInit, ViewChild } from '@angular/core';
import { ChildComponent } from '../child/child.component';

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

  
  @ViewChild(ChildComponent)
  child:ChildComponent;


  constructor() { }

 
  ngOnInit() {

    console.log("After init");

    console.log(this.child.country);
  }

  ngAfterViewInit(){

    console.log("After view init");
    console.log(this.child.country);
  }


  pingChild(){

   var message =  this.child.pingBack() + "-"+ this.child.name;

   alert(message);
  }

}

The below lines :

 @ViewChild(ChildComponent)
  child:ChildComponent;

instantiates a child component. The method pingChild() in the parent invokes the child method pingBack() and also refers to the child attribute “name”.

Here is the template code :



<app-child></app-child>

<br>


<button (click)="pingChild()"> Poke Child</button>

On click of ‘Poke Child’ button , the method pingChild() is called which in turn invokes the child’s method “pingBack” and also refers to its ‘name’ property.

All is well.

Notice that I also implemented two methods ngOnInit() and ngAfterViewInit().

This is to demonstrate when a child’s instance methods and properties are available within a parent component.

Usually these are available after the parent component and child components are initialized and hence available inside ngAfterViewInit() method.

ngOnInit() method may not have access to the child properties and methods.

I said ‘may not’ because I was able to access the child property “country” inside ngOnInit() method . I was also able to call child component’s method inside ngOnInit().

But this might not always work . It is always advisable to access a child component’s methods and properties inside ngAfterViewInit() method if you want them once the parent template is loaded.

This post concludes the series on angular component interaction using minimalist examples.

Here are the other posts in this series:

How to communicate through template reference?

How to communicate through a shared service?

How to communicate through @Input and @Output annotations?


Posted

in

,

by

Comments

Leave a Reply

Discover more from The Full Stack Developer

Subscribe now to keep reading and get access to the full archive.

Continue reading