The Angular @ViewChild decorator is one of the first decorators that you will run into while learning Angular, as it's also one of the most commonly used decorators.
This decorator has a lot of features: some of them might not be very well known but they are extremely useful.
In this post, we are going to quickly cover all the features that we have available in this decorator while giving practical examples for each use case along the way.
Table of Contents:
In this post, we will cover the following topics:
- When do we need the @ViewChild decorator?
- The AfterViewInit Lifecycle Hook
- What is the scope of @ViewChild template queries?
- using @ViewChild to inject a component
- how to use @ViewChild to inject a plain HTML element
- using @ViewChild to inject the plain HTML element of a component
- how to use @ViewChild to inject one of the multiple directives applied to a single element or component
- Code Samples (GitHub Repository)
So without further ado, let's get started with our @ViewChild decorator deep dive!
When do we need the @ViewChild decorator?
As we know, in Angular we define a component template by combining plain HTML elements with other Angular components.
As an example, we have here an Angular
AppComponent template that mixes both HTML and custom components in its template:
As we can see, this template includes several different elements types, such as:
- plain HTML elements like
- custom application components like the
- third-party components (like a color picker)
- as well as multiple Angular Material components
And this is what the
AppComponent looks like on screen:
We are going to base all our examples in this initial template. The
<color-sample> component is the little palette blue square, and next to it we have an input that is linked to a color picker popup.
When to use the @ViewChild decorator?
Many times we can coordinate these multiple components and HTML elements directly in the template by using template references like
#primaryColorSample, without using the
But this is not always the case! Sometimes, the
AppComponent might need references to the multiple elements that it contains inside its template, in order to mediate their interaction.
If that's the case, then we can obtain references to those template elements and have them injected into the
AppComponent class by querying the template: that's what @ViewChild is for.
Using @ViewChild to inject a reference to a component
Let's say that
AppComponent needs a reference to the
<color-sample> component that it uses inside its template, in order to call a method directly on it.
In that case, we can inject a reference to the
<color-sample> instance named
#primaryColorSample by using @ViewChild:
By using @ViewChild, the
primarySampleComponent member variable is going to be filled in by Angular with a
ColorSampleComponent instance is the same one linked to the
<color-sample> custom element present in the template.
When are variables injected via @ViewChild available?
The value of this injected member variable is not immediately available at component construction time!
Angular will fill in this property automatically, but only later in the component lifecycle, after the view initialization is completed.
The AfterViewInit Lifecycle Hook
If we want to write component initialization code that uses the references injected by @ViewChild, we need to do it inside the
AfterViewInit lifecycle hook.
Here is an example of how to use this lifecycle hook:
If we now run this program, here is the output that we get in the console:
As we can see, Angular has filled automatically our member variable
primaryColorSample with a reference to a component!
Can we use ngOnInit() instead of ngAfterViewInit()?
If we want to make sure that the references injected by @ViewChild are present, we should always write our initialization code using
Depending on the situation, the template references might already be present on
ngOnInit(), but we shouldn't count on it.
What is the scope of the @ViewChild template queries?
With @ViewChild, we can inject any component or directive (or HTML element) present on the template of a given component onto the component itself.
But how far can we query components down the component tree? Let's try to use @ViewChild to query a component that is deeper in the component tree.
As an example, let's have a look at the
As we can see, this component internally uses the
<mat-icon> component, to display the small palette icon.
Let's now go ahead and see if we can query that
<mat-icon> component and inject it directly into AppComponent:
If we try to run this, this is what we get in the console:
As we can see in the console results:
The @ViewChild decorator cannot see across component boundaries!
Visibility scope of @ViewChild template queries
This means that queries done using @ViewChild can only see elements inside the template of the component itself. It's important to realize that @ViewChild cannot be used to inject:
- Anything inside the templates of its child components
- and neither anything in the template of parent components as well
To summarize: the @ViewChild decorator is a template querying mechanism that is local to the component.
With this, we have covered the most common use case of @ViewChild, but there is still a lot more to it: let's see some more use cases!
Using @ViewChild to inject a reference to a DOM element
Instead of injecting a direct child component, we might want to interact directly with a plain HTML element of the template, such as for example the
h2 title tag inside
In order to do that, we need to first assign a template reference to the HTML tag that we want to inject:
As we can see, we have assigned the
#title template reference to the
h2 tag. We can now have the
h2 element injected directly into our component class in the following way:
As we can see, we are passing the string
'title' to the @ViewChild decorator, which corresponds to the name of the template reference applied to the
h2 is a plain HTML element and not an Angular component, what we get injected this time is a wrapped reference to the native DOM element of the
ElementRef simply wraps the native DOM element, and we can retrieve it by accessing the
nativeElement property, we can now apply any native DOM operation to the
h2 title tag, such as for example
And this is how we can use @ViewChild to interact with plain HTML elements in the template, but this leads us to the question:
What to do if we need the DOM element that is associated with an Angular component instead?
After all, the
<color-sample> HTML tag is still a DOM element, even though it has an instance of
ColorSampleComponent attached to it.
Using @ViewChild to inject a reference to the DOM element of a component
Let's give an example for this new use case. Take for example the
<color-sample> component inside
<color-sample> component has a template reference
#primaryColorSample assigned to it.
Let's see what happens if we now try to use this template reference to inject the
<color-sample> DOM element like we did with the
If we run this program, we might be surprised to find out that this time we are not getting back the native DOM element:
Default behaviour of @ViewChild injection by template reference
Instead, we are getting back again the
ColorSampleComponent instance! And this is indeed the default behavior of @ViewChild when using injection by template reference name:
when injecting a reference applied to a component, we get back the component instance
when injecting a reference to a plain HTML element, we get back the corresponding wrapped DOM element
The @ViewChild options argument
But in the case of our
<color-sample> component, we would like to get the DOM element that is linked to the component! This is still possible, by using the second argument of the @ViewChild decorator:
As we can see, we are passing a second argument containing a configuration object with the
read property set to
read property will specify exactly what we are trying to inject, in case that there are multiple possible injectables available.
In this case, we are using the
read property to specify that we want to get the DOM element (wrapped by
ElementRef) of the matched template reference, and not the component.
If we now run our program, this is indeed what we get in the console:
Let's now see another common use case when the @ViewChild
read property might come in handy.
Using @ViewChild to inject a reference to one of several directives
As our application uses more and more directives and libraries, we will likely need the
read property more and more.
For example, going back to our color picker example, let's now try to do something simple like opening the color picker when the color sample gets clicked:
In this example, we are trying to integrate our components by using template
We are detecting the click in
<color-sample>, and when that occurs we are trying to use the reference
#primaryInput to access the
colorPicker directive, and open the dialog.
Using template references is a good approach that will work in many cases, but not here!
In this case, the template reference
#primaryInput points to the DOM element
<input>, and not to the
colorPicker directive applied to that same element.
If we run this version of the program, we will get the following error:
This error occurs because, by default, the template reference
primaryInput points to the input box DOM element, and not to the
Using @ViewChild to inject Directives
As we can see, this is not the way to get a reference to a directive, especially in a situation when multiple directives are applied to the same plain HTML element or Angular component.
In order to solve this, we are going to first rewrite our template so that the handling of the click event is now delegated to the
Then in the
AppComponent class, we are going to have the color picker directive injected in the following way:
And with this, we now have a correct reference to the
If we now click on the small palette icon, the color picker will now get opened as expected:
And with this last example, we have now covered all the features of the @ViewChild operator, and some of their intended use cases. Let's now summarize what we have learned.
Code Samples (GitHub Repository)
All the running code for these examples can be found in the following GitHub repository.
The @ViewChild decorator allows us to inject into a component class references to elements used inside its template, that's what we should use it for.
Using @ViewChild we can easily inject components, directives or plain DOM elements. We can even override the defaults of @ViewChild and specify exactly we need to inject, in case that multiple options are available.
@ViewChild is a local component template querying mechanism, that cannot see the internals of its child components.
By injecting references directly into our component class, we can easily write any coordination logic that involves multiple elements of the template.
Why we don't always need @ViewChild
Let's also remember that there are many use cases when this decorator might not actually be needed, because many simple interactions can be coded directly in the template using template references, without the need to use the component class.
I hope that this post helps with better understanding @ViewChild, and that you enjoyed it!
If you have some questions or comments please let me know in the comments below and I will get back to you.
To get notified of upcoming posts on Angular Universal and other Angular topics, I invite you to subscribe to our newsletter:
Video Lessons Available on YouTube
Have a look at the Angular University Youtube channel, we publish about 25% to a third of our video tutorials there, new videos are published all the time.
Subscribe to get new video tutorials: