Edupala

Comprehensive Full Stack Development Tutorial: Learn Ionic, Angular, React, React Native, and Node.js with JavaScript

Guide to Using and Creating an Angular ViewChild Decorator?

Angular viewchild example

The Angular Viewchild() decorator allows us to get a reference to an element from a current component template. So that we can access, query, and manipulate HTML elements, child components, or directives in the parent components.

In this article, we’ll learn about the @viewChild decorator, we have three main objectives in this tutorial,

  1. What is @viewChild() decorator and when to use it?
  2. How do access an element in its own component template and access a child component or directive in the parent component?
  3. Demonstrate different scenarios where we can use 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 @ViewChild() and @ViewChildren() decorators provide a way to inject a reference to the HTML element/child component in our view component. In Javascript, we have a query selector like getElementsByClassName(), getElementsById(), in Angular provides a mechanism called DOM queries, using view It comes in the form of @ViewChild and @ViewChildren decorators. They behave the same, only the former returns one reference, while the latter returns multiple references as a QueryList object.

Syntax of ViewChild() decorator

<element #localReference>  
//Where element is HTML element or child component selector or decorator

#In component typescript we need to import viewChild decorator
 @ViewChild('localReference') localReference:ElementType;

Angular get element by id using @viewChild() decorator

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.

The 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.

In the @viewchild angular example, to demonstrate the Angular get element by ID, here we are adding a local reference to the second paragraph and adding style to it.

Angular get element by id
@Viewchild angular example
import { Component, ElementRef, ViewChild } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div>
      <p>First Paragraph</p>
      <p #secondP>Second Paragraph</p>   //Step1 add reference using #
      <p>Third Paragraph</p>
    </div>
  `,
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
//Step 2: set local variable in typescript
  @ViewChild('secondP') secondP: ElementRef |undefined;   

  ngAfterViewInit() {
    // Access it inside ngAfterViewInt
    this.secondP?.nativeElement.setAttribute("style", "color: blue; background-color:lightgray");
  }
}

How to use @viewchild() decorator?

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

  1. Define reference to DOM element in the component template using #referenceName
  2. In the 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 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. The @viewChild() decorator allows us to access and manipulate HTML element/child component/directive property directly into the class file of the parent component.

if you want to access the child component inside the parent, we can use the @viewChild decorator to access the child component. Thus @viewChild decorator gives a direct reference to the child controller. Use @viewChild decorator to only call child component properties and methods, it will save code and reduce coupling. But using the @viewChild decorator to access more than childs component properties and method, will increase coupling between components, which is not recommended, software should have less coupling and more cohesion.

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

We can apply 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.
The 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 the 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 the constructor and ngOnInit(), accessing it in this stage will return null. This is the reason we are getting 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.

We can access the property decorated with the @ViewChild only after the component’s View initializes. The “AfterViewInit” interface and corresponding method are the most appropriate place to access the ViewChild property. Accessing the @viewChild property in the constructor and ngOnInt will show Angular Viewchild undefined.
 @ViewChild('slider') slides:IonSlides;

  ngOnInit(){
    // <-- in here video is undefined
  }
  ngAfterViewInit(){
    console.log(this.slider.nativeElement) // <-- you can access it here
  }

ViewChild with Native HTML element: Angular ViewChild Example

Let’s first use the @viewChild decorator with a native HTML element in the component template. In the example below, we used 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
viewChild with HTML element

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

import { Component, ElementRef, ViewChild } from '@angular/core';
@Component({
  selector: 'app-root',
  template: `
    <div>
      <h3 #title>View child here...</h3>
    </div>
  `,
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  @ViewChild('title') title: ElementRef | undefined;

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

Using ViewChild to change HTML Element style in component typescript

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 a button, by clicking on a button will change our div container style using the viewChild. Here is a screenshot of our example.

ViewChild decorator to change element style
ViewChild decorator to change element style
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div div #divContent>
      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 the viewChild decorator and by clicking a button we are changing it font color of the 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 example addEventListener().


Using @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 properties.

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
cd 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 it manually in its 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.

viewchild with child component
Viewchild with child component

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

<div class="container">
  <h5>Parent component</h5>
  <button class="btn btn-primary" (click)="getAngularVersion()">
    Angular Version from child component
  </button>
  <button class="btn btn-primary" (click)="toggleChild()">
    Toggle child component
  </button>

  <div>Data from child Component : {{ angularVersion }}</div>
  <app-child #ChildComponent></app-child>
</div>

In the parent component, we use the 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 14.
2. Access child component toggle method to toggle its content hide/show child component template content.

import { Component, ElementRef, 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 {
  @ViewChild(ChildComponent) ChildComponent: any;

  angularVersion = '';

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

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

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

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

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

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

  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 viewChild with Directives

In our previous example, we have access viewChild on the 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.

viewchild decorator with directive
Viewchild decorator with the directive

Let’s 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’s 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’s 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. Our curry variable is an HTML text element and, we have added the value of the name and appended 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;
  }

}

I uploaded our ViewChild decorator example to stackblitz.com, if you want you can take reference on it.

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. I hope you had learned something, if so then please share it with others and on social networks, this will encourage me to add more content. Follow me on my GitHub collection, I had code on Angular, react, and Ionic framework.

Check articles on the best and latest 2022, and 2021 Angular books to read for your journey from beginner to advanced level. BEST BOOK ON ANGULAR 2022 – 2021

Related Post

Guide to Using and Creating an Angular ViewChild Decorator?

One thought on “Guide to Using and Creating an Angular ViewChild Decorator?

Leave a Reply

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

Scroll to top