Angular ViewChild decorator makes it possible to access a directive assigned to a particular element in the template. You could also use it to access a child component, or a DOM element from a parent component class together with ElementRef.
It’s used to reference or access template Dom elements and directives that belong to the same component. It’s also used to access methods, properties, and HTML Dom elements in different components.
Note: The initialization of the @viewChild() must always be done in the ngAfterViewInit() life cycle hook. It means your @viewChild() property will be ready after the ngAfterviewInit() hook is called.
What is the use of viewchild in angular?
Table of Contents
Viewchild is a decorator that configures a view query. The change detector uses it to search for the very first DOM element, component, or directive that matches the selector in the template. In short, it is mainly used to access Child/Sibling/Parent Components, Directive, or Dom Elements. Throughout this guide, I will show you different ways to access different parts of the Component and Dom elements.
How to access a template variable in a component using @ViewChild()
You can use angular @ViewChild ElementRef to access a template variable and also the element that a particular variable is assigned to.
To create a template variable use the hash (#) symbol followed by any character depending on your requirement. Then add the variable to the opening tag of the HTML element as shown below.
Inside the app.component.htm
l file…
<!--create a template variable called firstName -->
<input #firstName type="text" />
<button (click)="showValue()">Click</button>
From the above code, we have two elements, an <input>
and a <button>
tag. We have assigned a template-variable with the name #firstName
to the <input>
which we will access later in the component.
NB: Notice how we carefully created and assigned the variable to the HTML-Element.
We’ve also registered a function called showValue()
with a click event to the <Button> tag. The idea is to capture the data that will be entered into the input element from the component and print it or show an alert. Let’s now go ahead and work on the component file.
Inside the app.compont.ts
file
import { Component } from '@angular/core';
import { ViewChild, ElementRef } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent{
// pass a template variable to the @ViewChild("firstName")
// "firstName" below represent the #firstName variable in the html template
@ViewChild("firstName") firstNameRef!: ElementRef;
showValue(){
// below nativeElement returns the html tag <input>
var inputEle = this.firstNameRef.nativeElement.value;
alert(inputEle);
}
}
Inside the component, import ViewChild
and ElementRef
. Then we used the two to capture the template variable on this line above @ViewChild("firstName")
. Note that firstName
represents the variable defined in the template. Then to capture the <input>
tag itself, we use nativeElement.value
which will return the value that will be typed into it.
Then finally, we assigned it to a variable called inputeEle
and alert it in the showValue()
function or method above.
Note that ElementRef
is just a datatype that represents a reference to an HTML element. We need it because typescript requires types for such variables.
Accessing a template dom element in a component class with @ViewChild
To access a Dom element in a component, you can apply the same method we’ve discussed above using @ViewChild
First, assign a variable to the element you want to access in the template file.
<input type="text" #userName/>
Then inside app.component.ts
import ViewChild, ElementRef, and implement AfterViewInit and override it ngAfterViewInit method as shown below.
import {ElementRef, ViewChild, AfterViewInit } from '@angular/core';
// then let your component class implement "AfterViewInit" interface
export class AppComponent implements AfterViewInit {
// create a property of type "EmentRef" and decide which reference variable in the // dom you want it to be assigned
@ViewChild('userName') inputRef: ElementRef;
// overide the "ngAfterViewInit()" methode inside the "AfterViewInit" interface
ngAfterViewInit() {
// what do you want the dom element to do? Here it should be focus.
this.inputRef.nativeElement.focus();
//You can log it to the console and see some of it properties and methods you can use.
console.log(this.inputRef);
}
}
How to access Unrelated component’s properties & methods using Angular Viewchild
First, create a new component in a different module and make sure the component is not related to any other components. Then create a method showMsg()
that other components will call it.
Inside Second.component.ts
@Component({
selector: 'app-second',
templateUrl: './second.component.html',
styleUrls: ['./second.component.css']
})
export class SecondComponent {
constructor() { }
// create a method that will alert a messages
showMsg(){
alert("Inside second component");
}
}
Inside app.component.ts
Import ViewChild and use it to declare a property with a reference to the above SecondComponent. Then implements AfterViewInit and overrides it ngAfterViewInit method to initialize the property as shown in below code:
import { Component, ViewChild, OnInit } from '@angular/core';
import { SecondComponent } from './second/second.component';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
// Declare/Create a reference object that you will use to
// call metthods on the <SecondComponent>
@ViewChild(SecondComponent) secondComponent!:SecondComponent;
ngAfterViewInit(): void {
// initialize it
this.secondComponent = new SecondComponent();
}
// create a method that will be called on your templates
show(){
// call the showMsg() on the showMsg() method in <SecondComponent>
this.secondComponent!.showMsg();
}
}
Note, we have a method called show() in the above code. When this method is executed, it will call the showMsg()
function in the Second component. How do we call it? Let’s do that in the template file.
Inside app.component.html
<h1>Hello World?</h1>
<!--call the show() method in the app.component.ts file-->
<Button (click)="show()">show</Button>
When the “show” Button is called in the template, it triggers the show()
method, which also calls the showMsg()
method in the Second component. That’s how you access unrelated/sibling components with ViewChild but for some other reasons, this approach might not work when one component requires other dependencies.
How to access Child component properties & methods From A Parent Component with ViewChild
To access child components’ properties & methods from a parent component, simply create some method or property that the parent component will access with the help of ViewChild.
Inside child.component.ts
create a method called showMsg() that will alert the text “inside child Component”
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-child-component',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent {
constructor() { }
showMsg(){
alert("inside Child Component");
}
}
Inside app.component.html which is the parent component include the Child-Component template selector as shown below…
<h1>Hello World?</h1>
<!--call the show() method in the component-->
<Button (click)="show()">show</Button>
<!-- embed child Component template as child component-->
<!-- then create a reference variable #child_dom-->
<app-child-component #child_dom></app-second-component>
Inside app.component.ts
Import ViewChild and use it to declare a property that holds a reference of the Child component. But note that you don’t have to initialize it in the ngAfterViewInit method because the reference variable child_dom holds a reference to the Child Component in memory.
import { Component, ViewChild, OnInit, ElementRef } from '@angular/core';
import { Child} from './child/child.component';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent{
// Declare/Create a reference object
// grab the reference variable that represent the <SecondComponent> itself embeded int the app.component.html template
@ViewChild("child_dom") childComponent!:ChildComponent;
show(){
// call the showMsg() method in the <ChildComponent>
this.childComponent.showMsg();
}
}
Accessing a child component dom element using the @ViewChild({read}) property
The @viewChild has a “read” object property which indicates what exactly you want to grab on the reference variable.
For example, in Schoolroom, there are chairs, tables, students, and teachers. You can reference the School-room and use the “read” property to specify what specific item you want in the room.
Inside second.component.html
<p>Am second Components template</p>
Inside second.Component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-second-component',
templateUrl: './second.component.html',
styleUrls: ['./second.component.css']
})
export class SecondComponent {
constructor() { }
}
Inside app.component.hmtl
Include the child component in the template and assign it a reference variable that will be used to access it in the component.
<h1>Hello World?</h1>
<!--call the show() method in the component-->
<Button (click)="show()">show</Button>
<!-- embed secondComponent template as child component-->
<!-- then create a reference variable #scndcmpont-dom-->
<app-second-component #scndcmpont_dom></app-second-component>
Inside app.component.ts
Create a ViewChild property and set the {read: ElementRef} to access the template file of the second component as shown below.
import { Component, ViewChild, OnInit, ElementRef } from '@angular/core';
import { SecondComponent } from './second/second.component';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent{
// Declare/Create a reference object
// {read: ElementRef} = means read the element template of the SecondComponent
// becuase the "scndcmpont_dom" reference variable represnt the <SecondComponent.ts> itself not it template
@ViewChild("scndcmpont_dom", {read: ElementRef}) secondComponent!:ElementRef;
show(){
// grap the text <p>Am second Components template</p> in the secondcomponent template
console.log(this.secondComponent.nativeElement.innerText);
}
}
//result: Am second Components template
How to use the @viewChild({static: true | false}) property
The @viewChild({static: true | false}) helps you to specify when the initialization of the @viewChild() reference variable will be done.
- @viewChild({static: true}) Means the initialization of the @viewChild() reference variable should be done after ngOnInit() life-cycle hook is called. Meaning the reference variable can be accessed only when & after ngOnInit() is called.
- @viewChild({static: false}) Means the initialization of the @viewChild() reference variable should be done after ngAfterviewInit() life-cycle hook is called. Meaning the reference variable can be accessed only when & after ngAfterviewInit() is called.
- @viewChild() This is the default and is equal to @viewChild({static: false}) which means the initialization of the @viewChild() reference variable should be done when and after ngAfterviewInit() life-cycle hook is called.
Angular @ViewChild({static: false}) Ussage
Inside app.component.html create a paragraph with a reference variable #myparagraph
<h1>Hello World?</h1>
<!-- add a template reference variable 'myparagraph'-->
<p #myparagraph>This is a paragraph</p>
Inside app.component.ts use @ViewChild({static: false}) to declare a property that will holds the variable assign to the <p>
tag in the template. The {static: false}
the initialiation of the reference variable should be done after ngAfterViewInit is called.
import { Component, ViewChild, OnInit, ElementRef, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, AfterViewInit{
// Grap the "#myparagraph" in the template
// {static: false} meanst the initiliation should be available after ngAfterViewInit() is called
@ViewChild("myparagraph", {static: false}) parapgraph!: ElementRef;
// the above is the same as: @ViewChild("myparagraph") parapgraph!: ElementRef;
ngOnInit(): void {
console.log("inside ngOnInit");
/* This will be an error becuase the above @ViewChild("myparagraph") parapgraph!: ElementRef; has {static: false}
Which means the initialation of the @ViewChild("myparagraph") parapgraph!: ElementRef; should be availabe after ngAfterViewInit() is called
And since ngOnInit() is called before it, It can't find the "myparaph" tag
*/
console.log(this.parapgraph.nativeElement);
}
ngAfterViewInit(): void {
console.log("inside ngAfterViewInit");
/* This is correct becuase @ViewChild("myparagraph") parapgraph!: ElementRef; has a {static: false}
Which means the initialation of the @ViewChild("myparagraph") parapgraph!: ElementRef; should be availabe after ngAfterViewInit() is called
*/
console.log(this.parapgraph.nativeElement);
}
}
/*
RESULT:
inside ngOnInit
ERROR TypeError: this.parapgraph is undefined
inside ngAfterViewInit
<p #myparagraph>This is a paragraph</p>
*/
@ViewChild({static: true}) Ussage
Inside app.component.html
<h1>Hello World?</h1>
<!-- add a template reference variable 'myparagraph'-->
<p #myparagraph>This is a paragraph</p>
Inside app.component.ts
Note that {static: true} means the initialization of the reference variable should be done after ngInit method is called.
import { Component, ViewChild, OnInit, ElementRef, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, AfterViewInit{
// Grap the "#myparagraph" in the template
// {static: true} means the initiliation should be available after ngOnInit() is called
@ViewChild("myparagraph", {static: true}) parapgraph!: ElementRef;
ngOnInit(): void {
console.log("inside ngOnInit");
/* This is Correct.
{static: true} means the initialiation should be done here
*/
console.log(this.parapgraph.nativeElement);
}
ngAfterViewInit(): void {
console.log("inside ngAfterViewInit");
/*
This is Correct.
{static: true} means the initiliation was done in ngOnInit(). And since ngOnInit() was called before ngAfterViewInit()
the reference variable is availabe to be accessed here
*/
console.log(this.parapgraph.nativeElement);
}
}
/*
RESULT:
inside ngOnInit
<p #myparagraph>This is a paragraph</p>
inside ngAfterViewInit
<p #myparagraph>This is a paragraph</p>
*/
Note: If you want to Access multiple template reference variables with the same name and perform the above operation. Use @viewChildren() decorator.
Check also:
Angular 10 fundamentals for beginners
How to install angular CLI Easily
how to disable button on condition in angular
Angular generate component in a subfolder or subdirectory example