How to implement Angular ViewChild Decorator

Angular ViewChild and @ViewChildren decorators provide a way to inject a reference to the HTML element/child component in our view component. So that we can access, query, and manipulate the HTML element/child component directly inside the component typescript file. Angular provides a mechanism called DOM queries. It comes in the form of @ViewChild and @ViewChildren decorators. They behave the same, only the former returns one reference, while the later returns multiple references as a QueryList object.

In this article, we’ll learn what is viewChild, when to use it, and demonstrate different examples of viewChild decorator in an Angular.

What is angular viewChild decorator

The @ViewChild decorator allows you to retrieve and reference the component or directive from the current component View.

Angular get element by id

We can’t use Angular get element by id in Angular, but in regular JavaScript applications, we use a DOM selector like document.querySelector() or document.getElementById(), to get a reference to the DOM element. In javascript document.query.selector with id and class. In Angular, we can use the @ViewChild() decorator to get a reference to an element from a component template.

Angular viewChild decorator instructs the Angular DI framework to search for some specific first matching element/child component/directive in the component tree and inject it into the parent. This allows the parent component to interact with an element/child component in a template using the reference to communicate and manipulate its value in DOM.

Step of using Angular viewchild

Using viewChild decorator is easy, here we had listed abstract steps for accessing DOM elements in component typescript file.

  1. Define reference to DOM element in component template using #referenceName
  2. In component typescript file, import ViewChild decorator from ‘@angular/core’;
  3. In typescript component file, link template reference #referenceName to ViewChild variable by using @ViewChild(‘referenceName’) referenceName: ElementRef;
  4. Once we have referenceName property in typescript we can change the element style and content as like this. this.referenceName.nativeElement.innerHTML = ‘”Hi All’;

When to use angular viewChild decorator?

The template reference variable can access is limited only to the template and we can’t access directly in-class component. Angular viewChild() decorator allows us to access and manipulate element/child component/directive property directly into the class file of the parent component.

<input type="text" #name placeholder="Enter name"> OR 
<app-child #childComponent></app-child>

We can apply angular viewChild on the native HTML element or child component. We have two local template variables called #name and #childComponent with the hashtag. To uniquely identify the template elements, we need to use local template variables that start with the hash symbol. We have two examples above.
Angular ViewChild decorator is limited to injecting only children, so if you try to inject a component that isn’t a direct descendent, it will provide us with an undefined value.

When we can access angular viewChild decorator reference?

Properties decorated with @ViewChild are sure to be set before the ngAfterViewInit event hook on the component is called. This implies such properties are null if accessed inside the constructor. The reference to a @ViewChild variable is assigned once the View has been initialized. Once the View is initialized and rendered, in the ngAfterViewInit event hook we can access the template reference element.

Angular viewchild undefined

As we have learned that we can’t access the viewChild variable in constructor and ngOnInit(), accessing it in this stage will return null. This is the reason we are getting Angular viewChild undefined. To fix this issue, we can access the viewChild variable only after the view is initialized or in ngAfterViewInit. If you want to access in component template then add the ngIf directive on the viewChild variable until it is initialized.

 @ViewChild('slider') slides:IonSlides;
  ngOnInit(){
    // <-- in here video is undefined
  }
  ngAfterViewInit(){
    console.log(this.slider.nativeElement) // <-- you can access it here
  }

Using ViewChild with DOM Elements : Angular ViewChild Example 1

In the example below, we used angular viewChild to get a reference to h3 to change its innerHTML value. Once we had a reference to h3 we can do any changes to its style or content.

Angular viewchild example

Edit app.component.ts file for our example one.

import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';

@Component({
  selector: 'app-root',
  template:'<h3 #title>View child here...</h3>',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {
  @ViewChild('title') title: ElementRef;

  ngAfterViewInit() {
    this.title.nativeElement.innerHTML = 'Using viewChild to access innerHTML';
  }
}

Using ViewChild with DOM Elements : Angular ViewChild Example 2

In our previous example, we have an example of how to change the HTML native element innerHTML value and in this example, we will use viewChild to change the HTML element style. In the example below, we have div content and button, by clicking on a button will change our div container style using the viewChild. Here is a screenshot of our example.

Angular viewchild decorator style
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div div #divContent>
      Angular Viewchild to change color of div element to blue
    </div >
  <button (click)="changeStyle()" > Change Element styles </button>`,
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  @ViewChild('divContent') divContent: ElementRef;

  constructor() { }

  changeStyle() {
    this.divContent.nativeElement
    .setAttribute("style", "color: blue; width: 600px; height: 40px; background-color:     lightgray");
  }

}

We have used ElementRef to refer to an element of the DOM and ElementRef simply wraps the native DOM element. Angular ElementRef is a wrapper around a native element inside of a View. We need to import ElementRef from @angulare/core. The ElementRef has useful properties called nativeElement. We can use this native element property to access and manipulate the DOM element value and behavior.

In the example below, we are accessing the div element using angular viewChild decorator and by clicking a button we are changing it font color of element div to green font color. The @ViewChild() can instantiate ElementRef corresponding to a given template reference variable.

The template variable name in our case #divContent will be passed in @ViewChild() as an argument. In this way, the component will be able to change the appearance and behavior of the element of the given template variable. Using the nativeElement property, we can now apply any native DOM operation to the div tag, such as for example addEventListener().

Using Angular viewChild with Child Components

Angular @viewChild() decorator allows us to access a child component in the parent component. Once we have a reference on the child component, we can call child component methods or access its variables.

We can use the @ViewChild decorator to grab a reference to elements from the host view. In the example below, we have a child component selector as a reference in the parent component template. In the typescript file of the parent component, we can use this reference to directly access the child component properties and methods.

First, create a project and child component as

ng new viewChildApp
ng generate component child

By default generating component, it will declare automatically in the app.module.ts file. If a component is not declared in the app.module.ts file then we need to add and declare manually in it app.module.ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ChildComponent } from './child/child.component';

@NgModule({
  declarations: [
    AppComponent,
    ChildComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

By declaring it in the app.module.ts file we can access it from anywhere in our application. If we want to use this module in a specific module, we need to remove it from app.module.ts and declare it in that module only.

Angular viewChild component
Angular viewChild child component example

In the app.component.html as parent component, we have a button and also child component as

<div>
    <h2>Parent component</h2>
    <button (click)="getAngularVersion()">Angular Version ?</button>
    <button (click)="toggleChild()">Toggle child component</button>
</div>
<div>
    Data from child Component : {{ angularVersion }}
</div>
<app-child #ChildComponent></app-child>
<router-outlet></router-outlet>

In the parent component, we use angular viewChild decorator with reference to the child component instance to perform.
1. Access the child component property name to append it to the angular version 12.
2. Access child component toggle method to toggle its content hide/show.

import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { ChildComponent } from './child/child.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {
  @ViewChild(ChildComponent) ChildComponent;
  angularVersion: string;

  ngAfterViewInit() {
    setTimeout(() => {
      this.ChildComponent.name = this.ChildComponent.name + ' 11';
    });
  }

  toggleChild() {
    this.ChildComponent.toggle();
  }

  getAngularVersion() {
    this.angularVersion = this.ChildComponent.name;
  }
}

In the child component, we declare name property and method toggle.

import { Component } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `
  <div class="child" *ngIf="visible">
    <p> Control Child component content visibility from parent using viewChild.</p>
  </div>`,
  styleUrls: ['./child.component.scss']
})
export class ChildComponent {
  visible = true;
  name = 'Angular version';

  constructor() { }

  toggle() {
    this.visible = !this.visible;
  }
}

In the toggle method, we have property visible, by toggling it boolean value and using ngIf we can control child template visibility.

Using Angular viewChild with Directives

In our previous example, we have access viewChild on HTML DOM element and child component. In the same way, we can use ViewChild to access angular directives. In this example, we’ll use the viewChild decorator to access our custom directive in our parent component. Here is a screenshot of our example.

Angular viewChild on directive

Let add a food directive by using the following command.

ng generate directive food

This command will automatically declare food directives in our app.module.ts file. If our custom directive is not declared, then let declare it.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { FoodDirective } from './food.directive';

@NgModule({
  declarations: [
    AppComponent,
    FoodDirective
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Let edit our food.directive.ts file, we have a name property and we have to create a text element and append it to our directive. In our curry variable is an HTML text element and, we have added the value of the name and append it with five emoji curry.

import { Directive, ElementRef, Renderer2 } from '@angular/core';

@Directive({
    selector: '[appFood]'
})
export class FoodDirective {
    name = 'India Curry : ';

    constructor(elem: ElementRef, renderer: Renderer2) {
        let curry = renderer.createText(this.name + '🍛🍛🍛🍛🍛');
        renderer.appendChild(elem.nativeElement, curry);
    }
}

The renderer2 is Angular’s View Engine from Angular 4 onward till Angular 8, it was the responsibility of the view engine to compile components to JS and HTML. Angular Renderer2 class is an abstraction provided by Angular in the form of a service that allows manipulating elements of your app without having to touch the DOM directly.

Next, we will add our custom food directive in our parent component template: app.component.ts

<h2>Viewchild decorator on directive</h2>
<span appFood></span>

Now, we can access the name property instance variable of FoodDirective and set a food instance variable with its value from our food directive.

import { Component, ViewChild } from '@angular/core';
import { FoodDirective } from './food.directive';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  food: string;

  @ViewChild(FoodDirective) set appFood(directive: FoodDirective) {
    this.food = directive.name;
  }

}

Conclusion
We have explored what is viewChild decorator and how viewChild decorator allows us to get references on DOM elements, directives, or components. With this reference, we can manipulate or access reference properties.

Related Post

Spread the love

1 thought on “How to implement Angular ViewChild Decorator”

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top