Technouz

Using @ViewChild in Angular

By Zahid Mahmood / 23 June 2021

A ViewChild is a reference to a component, directive or element within the template of the current component. We can use the @ViewChild() decorator to access the child component from the parent component.

When to use the @ViewChild decorator?

Often you might see template references being used to access elements directly. For example, the #name template reference might be used to get the value of the input field in the example below:

<input #name placeholder="Enter your name" />
<p>Hi {{name.value}}</p>

But sometimes you may need to access the entire <input /> component from within the controller. Order, you want better access to public methods on a custom component.

For example, take this template which contains a custom input field for currency:

<div>
    <p>Enter an amount:</p>
    <app-currency-input></app-currency-input>
<div>

<app-currency-input> is a custom Angular component called CurrencyInputComponent.

We can now use @ViewChild to inject a reference to the AppCurrencyInputComponent from within our controller like so:

...
export class AppComponent {
    @ViewChild(CurrencyInputComponent) currencyInput: CurrencyInputComponent;
    ...
}

Is there a difference between the template reference and the ViewChild reference?

No. The injected CurrencyInputComponent instance would be the same one had we use a template reference instead.

When is the ViewChild variable initialised?

The value of the ViewChild variable is not immediately available when the component is constructed. Angular will automatically initialise the value when it's ready, but this will only be in the AfterViewInit lifecycle hook.

That means you'll need to tread carefully if you're using the OnInit lifecycle hook because there is a chance the value will be undefined.

Here is an example of accessing a ViewChild in the ngAfterViewInit lifecycle hook:

...
@ViewChild(CurrencyInputComponent) currencyInput: CurrencyInputComponent;

ngAfterViewInit() {
    console.log("currencyInput @ViewChild", this.currencyInput);
}

Depending on the context, there is a chance that the ViewChild might already be initialised in the ngOnInit lifecycle hook, but we should not count on it. It is always better to execute any logic which relies on the reference within ngAfterViewInit to ensure your code is more robust and testable.

Accessing methods within a ViewChild component reference

Once you have access to the component via ViewChild it's possible to access public properties and methods on that component. This feels strange initially because it begins to couple a parent component to a child component but it's also a great way to encapsulate related logic within a component and have the parent component orchestrate the execution.

Whilst there is nothing wrong with using a ViewChild reference to execute methods within a child component, you'll need to be mindful of the component API you create. For example, marking class variables and methods as private, protected and public will go a long way. Any methods marked as public will be accessible through the ViewChild reference and therefore can be executed ad-hoc. Make sure your code is written in a way that can handle this scenario.

Take for example, our currency input component above which has a public method to convert the input to Canadian Dollars:

@Component({
  selector: 'app-currency-input',
  templateUrl: './currency-input.component.html'
})
export class CurrencyInputComponent {
    ...

    public convert(currency: string) {
        // logic to convert
    }
}

Our parent component can create a ViewChild reference and call the convert() method.

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
    @ViewChild(CurrencyInputComponent) currencyInput: CurrencyInputComponent;

    ...

    handleButtonPress() {
        this.currencyInput.convert("CAD");
    }
}

Thanks for reading!

My name is Zahid Mahmood, and I'm one of the founders of Anterior. I started this technology blog when I was in high school and grew it to over 100,000 readers before becoming occupied with other projects. I've recently started writing again and will be posting more frequently.