Angular ElementRef | Angular ViewChild & ViewChildren - Accessing Elements Correctly
In this post you will learn what is ElementRef
, ViewChild
and ViewChildren
inside Angular.
Here I already prepared for us a small component. I created a child
component with several methods.
export class ChildComponent {
count = 0;
increment() {
this.count++;
}
decrement() {
this.count--;
}
}
Here is our child template
{{count}}
This is just a small component with counter and 2 methods. And inside our parent we render our child component.
<child></child>
In browser we just rendered zero and nothing more.
View child
What we want to do now is increase our child's counter from the parent. In order to do that I want to create a button.
<button (click)="increment()">Increment child</button>
<child></child>
How we can access a child component and run it's function when we click on the button?
export class AppComponent {
@ViewChild(ChildComponent, {static: true}) child?: ChildComponent;
increment() {
this.child?.increment();
}
}
Here we used ViewChild
where we pass our ChildComponent
in order to get access of the component that we rendered in markup. Static true means that we are sure that this component is always there and it is not wrapped in some if condition.
This allows us to call this.child?.increment()
inside to change the counter.
As you can see now we can increase our counter from the parent component.
ViewChild allows us to get access to the child component and do whatever we want with it.
But I must tell you that it is not the best approach. The default way to do something like this is Angular is by using Inputs
and Outputs
. Which actually means your child must have an Output
increment if you want to allow changing it from outside. We should not brutforce this increment
method through ViewChild
if we can avoid it.
We can also use ViewChild
not only with components but also with DOM elements.
<button (click)="increment()" #button>Increment child</button>
<child></child>
Here I added #button
on our HTML element which allows me to get access to it in the component.
export class AppComponent implements AfterViewInit {
@ViewChild('button', {static: true}) buttonRef?: ElementRef<HTMLButtonElement>;
ngAfterViewInit() {
if (this.buttonRef?.nativeElement) {
this.buttonRef.nativeElement.innerHTML = 'fooo'
}
}
}
Here we used ViewChild
to get an HTML element. We wrote code related to it in ngAfterViewInit
because we want to be sure that our DOM element is already rendered. Then we changed the text of the button to fooo
.
As you can see in browser we successfully changed the text of the button through DOM access.
View children
If you have several elements on the screen it makes a lot of sense to use ViewChildren
in order to get access to them as an array. But in order to test that let's add several components inside.
<child></child>
<child></child>
<child></child>
export class AppComponent {
@ViewChildren(ChildComponent, {static: true}) children?: QueryList<ChildComponent>;
ngAfterViewInit() {
this.children?.forEach(child => console.log(child))
}
}
The code is super similar but we get back a QueryList
which is an array of DOM elements.
As you can see we got access to the list of our children components.
In the same way we can get access to the list of DOM elements.
export class AppComponent implements AfterViewInit {
@ViewChildren('button', {static: true}) buttonsRef?: ElementRef<HTMLButtonElement>;
ngAfterViewInit() {
this.buttonsRef?.forEach(button => console.log(button))
}
}
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!