DEV Community

Anubhab Mukherjee for This is Angular

Posted on

Understanding ViewChild and ViewChildren in Angular

Today we will learn a very important and powerful concept in Angular - the ViewChild and ViewChildren

On a high level ViewChild and ViewChildren both are property decorators.
With this decorators we can -
1๏ธโƒฃ Access an element present in the same template (html) of the component
2๏ธโƒฃ Access the child component

So we can say it's used to access elements present in the template.

The Syntax
@ViewChild(selector, {read: readValue, static: staticValue})
propertyName

I will touch upon the syntax as and when we need them.

So what we will achieve at the end of this demo?
We will create a counter component. It will have a counter initialized to 0. There will be two methods one to increase the counter by x amount and the other to reduce by x amount.
The component methods will be accessed or you can say called from the parent only.

Lets setup our playground first.
Lets create a component called my-counter and make it a child component of app-component. If you are wondering how to make a child component? Please have a look at this post before moving ahead.

Once we create the component, lets open the my-counter component ts file and add the below code-

  counter = 0;
  constructor() { }
  ngOnInit(): void { }

  increaseCounter(x: number) {
    this.counter += x;
  }

  decreaseCounter(x: number) {
    this.counter -= x;
  }
Enter fullscreen mode Exit fullscreen mode

Image description
And in the corresponding template file -

<p>Counter Value: {{ counter }}</p>
Enter fullscreen mode Exit fullscreen mode

Now lets move to the app.component.ts file and the following code -

  increaseCounter(x: number) { }

  decreaseCounter(x: number) { }
Enter fullscreen mode Exit fullscreen mode

We will add the method body soon.
And in the corresponding template the following code -

<input (click)="increaseCounter(1)" type="button" 
value="Add by 1">

<input (click)="decreaseCounter(1)" type="button" 
value="Subtract by 1">
Enter fullscreen mode Exit fullscreen mode

Output till now -
Image description
And the button does nothing. But it will do ๐Ÿคž

Now lets come to the real part -

We will see ViewChild first.
So lets add a property in app.component ๐Ÿ‘‰ counterReference.
The property counterReference will be holding a reference of the Counter component. So we will assign -

counterReference = {} as MyCounterComponent;
Enter fullscreen mode Exit fullscreen mode

and also decorate it with ViewChild. So the final code will become -

  @ViewChild(MyCounterComponent)
  counterReference = {} as MyCounterComponent;
Enter fullscreen mode Exit fullscreen mode

The viewChild accepts few parameters.
The first parameter is the Component which you want to select or get the reference (in this case). You can also query using a templateReference (which I will show soon).
Now lets complete the 2 functions which we kept empty -

  increaseCounter(x: number) {
    this.counterReference.increaseCounter(1);
  }

  decreaseCounter(x: number) {
    this.counterReference.decreaseCounter(1);
  }
Enter fullscreen mode Exit fullscreen mode

Here in the above code you can see with the property counterReference decorated with ViewChild we can access the child component MyCounterComponent (methods).

When you click any of the button you will see the Counter value is getting changed.
Image description

So from the parent you can access the child methods.

Cool right?
Now the next variation (as I said earlier) using template reference.
Example of a template reference -

<div #myTemplateRef></div>
<app-my-counter #componentTemplateRef></app-my-counter>
Enter fullscreen mode Exit fullscreen mode

Observe the # (pound symbol).
It is a variable to reference the DOM within a template. Here myTemplateRef or componentTemplateRef is the template reference.

Lets add few more lines of code to see how it works. Add the below lines of code in component.ts file-

  @ViewChild('myTemplateRef')
  myTemplateRef = {};

  @ViewChild('componentTemplateRef')
  componentTemplateRef = {};
Enter fullscreen mode Exit fullscreen mode

And in the corresponding template file -

<div #myTemplateRef></div>
<app-my-counter #componentTemplateRef></app-my-counter>
Enter fullscreen mode Exit fullscreen mode

Now a very important piece of information -

You might have seen a method that gets generated when you create a component using CLI - the ngOnInit()
This is a Angular lifecycle hook method. I will talk about the Lifecycle Hooks in details in the upcoming post.
Similar to this method there is another life cycle hook method called ngAfterViewInit().
So, when ever the template/ view initialization is complete or I can say view is ready the ngAfterViewInit() method is called and all the properties decorated with viewChild are ready to use. Before that they are uninitialized/ undefined.
In the ngOnInit the properties would look like below -
Image description
And in the ngAfterViewInit the properties would look like -
Image description
In summary a quick pictorial representation -
Image description

static:
By default the value of static is false.

The true value is used to support creating embedded view on the runtime. When I will write about creating dynamic component again I will talk about static: true.


Now coming to ViewChildren. It is very similar to ViewChild except it provides a collection of matching references as a QueryList of items.

QueryList - Its an unmodifiable list of items that Angular keeps track of and up to date when the state of the application changes.

There are few properties and methods of QueryList
first: gets the first item in the list.
last: gets the last item in the list.
length: gets the length of the items.
changes: An observable. It emits a new value, whenever the Angular adds, removes or moves the child elements.

JavaScript array methods like map(), filter() , find(), forEach(), etc. are also supported by the QueryList

Now the example -
You have three entries of the same component ๐Ÿ‘‡

<app-my-counter></app-my-counter>
<app-my-counter></app-my-counter>
<app-my-counter></app-my-counter>
Enter fullscreen mode Exit fullscreen mode

And you want to get hold of all the items.
ViewChildren is the best choice.

  @ViewChildren(MyCounterComponent)
  viewChildrenRef: QueryList<MyCounterComponent> | undefined;
Enter fullscreen mode Exit fullscreen mode

Here using ViewChildren you can get access to all the matching selector. You can loop through them and perform any operation you need to.

That's all for now.

Hope you enjoyed reading the post

If you liked it please like โค๏ธ share ๐Ÿ’ž comment ๐Ÿงก.

Coming up more topics on Angular.
So stay tuned.

I will be tweeting more on Angular JavaScript TypeScript CSS tips and tricks.

So hope to see you there too ๐Ÿ˜ƒ

Cheers ๐Ÿป
Happy Coding

Discussion (2)

Collapse
oliverdjbrown profile image
Oliver Brown

excellent article

Collapse
anubhab5 profile image
Anubhab Mukherjee Author

Glad you liked it Oliver