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;
}
And in the corresponding template file -
<p>Counter Value: {{ counter }}</p>
Now lets move to the app.component.ts file and the following code -
increaseCounter(x: number) { }
decreaseCounter(x: number) { }
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">
Output till now -
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;
and also decorate it with ViewChild. So the final code will become -
@ViewChild(MyCounterComponent)
counterReference = {} as MyCounterComponent;
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);
}
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.
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>
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 = {};
And in the corresponding template file -
<div #myTemplateRef></div>
<app-my-counter #componentTemplateRef></app-my-counter>
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 -
And in the ngAfterViewInit
the properties would look like -
In summary a quick pictorial representation -
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>
And you want to get hold of all the items.
ViewChildren
is the best choice.
@ViewChildren(MyCounterComponent)
viewChildrenRef: QueryList<MyCounterComponent> | undefined;
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
Top comments (2)
excellent article
Glad you liked it Oliver