Skip to content

Angular ViewChild

Angular View Child Cover

We are not stopping with the decorators here. The next one we’ll tackle is the @ViewChild. Additionally, you can get a refresher on @ContentChild and @ContentChildren.

We’ve seen how @ContentChild and @ContentChildren work. Components are queried based on what we pass inside the component tags. Take a look at the snippet below, from our little card project:

<app-user-card>
  <div class="more-data" fav-day>
    <h3>Favorite day:</h3>
    <p>Sunday</p>
  </div>
  <div class="more-data" dislikes>
    <h3>Dislikes:</h3>
    <p>The alarm clock</p>
  </div>
  <div class="more-data" expiry #expiry>
    <h3>Expiry Date:</h3>
    <p>20/05/2024</p>
  </div>
</app-user-card>

Everything inside the <app-user-card> is considered to be a content child, and as such, they can be queried as content children. Another way to query and dynamically create components is using @ViewChild and @ViewChildren decorators.

@ViewChild

Ok, let us briefly touch on some theory regarding @ViewChild.

It is another property decorator that configures a query. But this time we are utilizing the change detector that searches for the first element or directive matching the selector. If the selector matches, we update the property and DOM accordingly.

For @ViewChild we are using a new callback ngAfterViewInit (more on that later). As with the content decorators, we are providing a selector which is the directive type or the name we are using. Again, we can use components, directives, template references, tokens… We also have a static property, which takes a boolean value and is completely optional. By default, it is false, meaning that it is resolved after the component view properties are initialized. If it is true though, you guessed it, it is resolved before that (we will see how all of this fits in the preceding example).

When to use @ViewChild? We can use the decorator anytime where we dynamically want to add, access, or modify elements, or in cases in which we can’t work on elements conventionally. Also, we would use @ViewChild in cases where we would like to gain access to everything public (properties and methods) inside the child component.

Let us look at an example.

Using @ViewChild

Let us add another section to our card. It will be a simple section titled ‘id’, which will again be a random string that would represent a person’s id. But this time, instead of just inserting HTML code, we will create a completely new component. This is the HTML of the new IdComponent.

<p
  [ngStyle]="{
    'background-color': backgroundColor,
    color: foregroundColor,
    'font-weight': fontWeight
  }"
>
  129301040941904109
</p>

And the class itself:

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

@Component({
  selector: 'app-id',
  templateUrl: './id.component.html',
  styleUrls: ['./id.component.css'],
})
export class IdComponent implements OnInit {
  fontWeight: string;
  backgroundColor: string;
  foregroundColor: string;

  constructor() {}

  ngOnInit() {}
}

It is a simple component with basic string properties, that are inserted via the ngStyle decorator as key-value pairs, and are actually responsible for changing the styling of our id template. Let us include the new component in our user-card.component.html template.

<!-- only a part of the template -->
    <div class="personal-data">
      <h3>Name:</h3>
      <p>Tom</p>
      <h3>Surname:</h3>
      <p>Doe</p>
    </div>
  </div>
  <app-id></app-id>
  <div class="more-data">
    <h3>Likes:</h3>
    <p>Football, swimming, beer</p>
    <div class="more-data" fav-day>
      <h3>Favorite day:</h3>
      <p>Sunday</p>
<!-- only a part of the template -->

And how does this look?

@ViewChild – the new Id Component

Looks basic enough right? Now you might wonder, we have those properties bound to the IdComponent, how can we utilize them? Well, take a look at the snippet below.

import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';
import { IdComponent } from '../id/id.component';

@Component({
  selector: 'app-user-card',
  templateUrl: './user-card.component.html',
  styleUrls: ['./user-card.component.css'],
})
export class UserCardComponent implements OnInit, AfterViewInit {
  @ViewChild(IdComponent)
  idComponent: IdComponent;

  constructor() {}

  ngOnInit() {}

  ngAfterViewInit() {
    this.idComponent.foregroundColor = 'maroon';
    this.idComponent.backgroundColor = 'mintcream';
    this.idComponent.fontWeight = 'bold';
  }
}

Let us come back to the ngAfterViewInit hook. What does it do? Well, we are using it simply because the values of injected members are not available at the constructed or initialized time. If we want to create/create references using @ViewChild we need to put them inside ngAfterViewInit.

Then we have this:

 @ViewChild(IdComponent) idComponent: IdComponent;

This is the way how we actually query the component. By using the reference (IdComponent) as the selector the compiler knows automatically which component we are looking for. How cool is that!

What else can we do with @ViewChild?

@ViewChild and DOM references

We can also reference a direct HTML element. Let us assign a template reference to one of the elements.

<!-- only a part of the template -->
    <div #personalData class="personal-data">
      <h3>Name:</h3>
      <p>Tom</p>
      <h3>Surname:</h3>
      <p>Doe</p>
    </div>
<!-- only a part of the template -->

Now we can use the template reference named #personalData in order to inject it directly into our component:

  @ViewChild('personalData') personalData: ElementRef;

Here we are passing the string 'personalData' to the decorator, instead of the component name. Using the string we are actually searching for a template reference, which we have in our template.

Then we can log out the element itself.

  ngAfterViewInit() {
    this.idComponent.foregroundColor = 'maroon';
    this.idComponent.backgroundColor = 'mintcream';
    this.idComponent.fontWeight = 'bold';

    console.log(this.personalData);
  }

We can also change the styling of our element! For that, we would need to use a Renderer, but we won’t cover it in this blog post. But we can add listeners to the element, and other native DOM operators.

For the complete project, please look at the Stackblitz below:

Final Words

@ViewChild is probably the most commonly used query decorator in Angular, and it shows. Allowing us to inject component or directive references, or even plain DOM elements it is a highly versatile tool, for dynamical content.

For more articles please click below, or check the blog.