Simplifying @ViewChild And @ViewChildren In Angular

Most of the times when we need to change the behavior or appearance of an element in our template from our component class (i.e. from TS file). we require a reference variable of that element. For this, in View (HTML) we can use template reference variable, but how can we get this variable into our component class?

For this, we can either use @ViewChild or @ViewChildren. Here we are going to understand when we need to use @ViewChild and @ViewChildren. 
 
Let's understand this with an example.

Create a new component called “first” using the following command,
  1. ng g c first  
After that, write the following code in “first.component.html” file.
  1. <div class="row">  
  2.   <button type="button" class="btn btn-primary">My Button</button>  
  3. </div>  
If we want to take the reference of this element (i.e. button) in our component class, then we have to declare a local reference variable.
  1. <div class="row">  
  2.  <button type="button" class="btn btn-primary" #myButton>My Button</button>  
  3. </div>  
Now, in our component class, to get the reference of this button, we use @ViewChild decorator function.
  1. @ViewChild("myButton") myValue:ElementRef;  
Look at the picture for understanding the above line.
 
Angular 

@ViewChild decorator means to search for that element inside the component’s template. The parameter we passed as the first argument in the ViewChild, is the type of the component or the reference we want to search for. If it finds more than one it returns us the first one that it found.

@ViewChild returns a reference of an element so, we can use “ElementRef” to define the type of variable.

Let's print the above variable (‘myValue’) into the console.
  1. @ViewChild("myButton") myValue:ElementRef;  
  2.  constructor() {  
  3.    console.log(this.myValue);  
  4. }  
Save and run the application and see the output.
 
Angular
As we have seen in the above output, if we want to print this reference into the constructor, then it shows undefined. Now, the question is, Why did it show undefined inside the constructor and how can we use it?

It showed undefined inside the constructor because, at the time when constructor was called, angular didn't render the children.

As we know, all the data renders in a Tree-Down approach in angular, so, when a parent component is constructed it means the child is not created yet.

So, to get the value of this reference we require component hook (which we have already discussed in component lifecycle hook article).

Here, we use either ngAfterViewInit or ngAfterViewChecked hook. Now, in this, we are going to use ngAfterViewInIt and inside this hook method we will print the value of reference variable like:
  1. ngAfterViewInit(){  
  2.    console.log(this.myValue.nativeElement);  
  3.  }  
Angular
 
Now, we can say that we can easily access our reference variable with the help of @ViewChild. But, what can we do if we want to get the ViewChild of any component that has been used within this component? (To get the reference of child component into parent component) Like,

First, generate one more component called “clock”, by the following command,
  1. ng g c clock  
Now, to create Clock component as a child of First Component, called “app-clock” selector inside the “first.component.html” file like,
  1. <div class="container">  
  2.    <div class="row mt-2 mb-2 text-center">  
  3.      <div class="col-lg-12 col-md-12 col-sm-12">  
  4.       <app-clock></app-clock>  
  5.     </div>  
  6.    </div>  
  7.    <div class="row mt-2 mb-2 text-center">  
  8.      <div class="col-lg-12 col-md-12 col-sm-12 col-12">  
  9.       <button type="button" class="btn btn-primary" #myButton>My Button</button><br>  
  10.     </div>  
  11.     </div>  
  12. </div>  
Go to the “clock.component.ts” file, and declare a variable of date type like,
  1. today:Date=new Date();  
Now, go to the “clock.component.html” file and write the following code,
  1. <div class="clock bg-danger text-white">{{today|date:'mediumTime'}}</div>  
See, the output,
 
Angular 
Now, if we want to access this property (today) of child component into parent then how can we do this?

For this, we create a reference of child element into parent component class. For this, we need to follow the following steps
 
Step 1

Import the child component (clock) into the parent component (first.component.ts) file,
  1. import { ClockComponent } from './../clock/clock.component';  
Step 2

Create a component type reference with the help of @ViewChild() like,
  1. @ViewChild(ClockComponent) myValue:ClockComponent;  
Step 3

Use child variable inside ngAfterViewInit() inside parent’s component. Like this,
  1. ngAfterViewInit(){  
  2.    setInterval(()=>{  
  3.      this.myValue.today=new Date();  
  4.    },1000)  
  5.  } //use set interval, so that time will be change (a running clock)  
Angular 
See the above output, we change the time in parent’s component by setInterval. Basically, when we run it, it runs a clock. I hope so far you understand what  @ViewChild is and when to use it. 
 
What is @ViewChildren?

Now, what do we need to if we want to access a value from multiple child components? Like  this:
  1. <div class="container">  
  2. <div class="row mt-2 mb-2 text-center">  
  3.   <div class="col-lg-12 col-md-12 col-sm-12">  
  4.    <app-clock></app-clock>  //Child component (Use 1st time)  
  5.  </div>  
  6. </div>  
  7. <div class="row mt-2 mb-2 text-center">  
  8.   <div class="col-lg-12 col-md-12 col-sm-12">  
  9.    <app-clock></app-clock>  //Child component (Use 2nd time)  
  10.   </div>  
  11. </div>  
  12. <div class="row mt-2 mb-2 text-center">  
  13.   <div class="col-lg-12 col-md-12 col-sm-12 col-12">  
  14.    <button type="button" class="btn btn-primary" #myButton>My Button</button><br>  
  15.  </div>  
  16.  </div>  
  17. </div>  
See the output,
 
Angular 
Now, in above output, two elements rendered and we are able to see two clocks, but in the console only one reference is present. So, now to get multiple children components we can use @ViewChildren() decorator.
 
Let’s understand this by an example,

Go to the first.component.ts file and change “ViewChild()” to “ViewChildren()” like,
  1. @ViewChildren(ClockComponent) myValue:QueryList<ClockComponent>;  
Here, @ViewChildren will return a list of elements, so, we also require QueryList, to get the list of this type of component. See the output,
 
 Angular
 
In the above output, at console screen, we are able to see the list inside the QueryList.
 
For more readability, we convert it into the array like this.
  1. ngAfterViewInit(){  
  2.    console.log(this.myValue.toArray());  
  3.  }  
See the output,
 
Angular 
Conclusion

@ViewChild() provides the instance of another component or directive in a parent component and then parent component can access the methods and properties of that component or directive. In this way, by using @ViewChild() a component can communicate with another component or a directive. But if we want to access multiple child references then we have to use @ViewChildren.
 
Now, we have learned about @ViewChild and @ViewChildren from this article. For practice purposes, here, a sample project called “SampleViewChild” is attached which covers all the code. You can download and modify this as per your requirement. All your queries related to this article and sample project are always welcome. Thanks for reading.