@ViewChild and @ViewChildren in Angular - Part 2

Gurinderpal Singh Narang
3 min readNov 6, 2023

--

We discussed in the preview blog that the @ViewChild and @ViewChildren decorators in Angular are primarily used for querying elements in the template, but they can also be used for some other purposes beyond just selecting template elements. Here are a few scenarios where these decorators can be useful apart from querying the template:

  1. Component Communication:
    We can use @ViewChild and @ViewChildren to establish communication between child and parent components. We can use @ViewChild to get a reference to a child component and call methods or access properties on that component.
  2. Accessing Child Component Instances:
    We can use @ViewChild to access instances of child components. This can be useful when we need to interact with child components or retrieve data from them.
  3. Lifecycle Hook Manipulation:
    We can use @ViewChild to trigger lifecycle hooks in child components. For example, we can programmatically call ngOnInit, ngOnChanges, or other lifecycle hooks on child components.

Accessing Child Component Instances and Communication b/w Components

Suppose we have a parent component (ParentComponent) that includes a child component (ChildComponent). We want to access the instance of ChildComponent from ParentComponent and interact with it.

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

@Component({
selector: 'app-child',
template: `
<h2>Child Component</h2>
<button (click)="childMethod()">Call Child Method</button>
`,
})
export class ChildComponent {
childData: string = 'Data from Child';

childMethod() {
console.log('Child component method called');
}
}
import { Component, ViewChild } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
selector: 'app-parent',
template: `
<h1>Parent Component</h1>
<p>{{ child.childData }}</p>
<button (click)="callChildMethod()">Call Child Method</button>
<app-child #child></app-child>
`,
})
export class ParentComponent {
@ViewChild('child', { static: true }) child: ChildComponent;

callChildMethod() {
this.child.childMethod(); // Call the child component's method
}
}

This example demonstrates how we can access the instance of a child component from the parent component and call methods on the child component or access its properties.

  • ParentComponent uses the @ViewChild decorator to access the instance of ChildComponent. We specify the template reference variable #child to identify the child component.
  • callChildMethod in ParentComponent is a method that calls a method defined in the child component, childMethod.
  • The child component has a button that, when clicked, calls the childMethod.

With this setup, when we load the application, we’ll see the “Call Child Method” button in both the parent and child components. Clicking the button in the parent component will call the childMethod in the child component, and we'll see the "Child component method called" message in the console.

Similarly, to our previous example, the @ViewChild decorator is used to access a child component's instance and manipulate its lifecycle hooks. Let's explore an example of how to do this:

Suppose we have a parent component (ParentComponent) with a child component (ChildComponent). We want to programmatically trigger the ngOnInit and ngOnChanges lifecycle hooks of the child component from the parent component.

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

@Component({
selector: 'app-child',
template: `<h2>Child Component</h2>`,
})
export class ChildComponent implements OnInit, OnChanges {
ngOnChanges(changes: SimpleChanges): void {
console.log('ChildComponent - ngOnChanges', changes);
}

ngOnInit(): void {
console.log('ChildComponent - ngOnInit');
}
}
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
selector: 'app-parent',
template: `
<h1>Parent Component</h1>
<button (click)="triggerChildLifecycleHooks()">Trigger Child Hooks</button>
<app-child #childComponent></app-child>
`,
})
export class ParentComponent implements AfterViewInit {
@ViewChild('childComponent') child: ChildComponent;

ngAfterViewInit() {
// Access the child component
}

triggerChildLifecycleHooks() {
// Programmatically trigger child component's lifecycle hooks
this.child.ngOnChanges({});
this.child.ngOnInit();
}
}

In this example:

  • The ChildComponent has both ngOnInit and ngOnChanges lifecycle hooks, which log messages to the console when they are triggered.
  • The ParentComponent uses @ViewChild to access the instance of ChildComponent and provides a button to trigger the child component's lifecycle hooks.
  • The triggerChildLifecycleHooks method in the ParentComponent programmatically calls the ngOnChanges and ngOnInit lifecycle hooks of the child component.

Note: Manipulating lifecycle hooks in this manner is not a common practice and should be used with caution. It’s essential to understand the implications of manually triggering these hooks and ensure that they align with our application’s requirements.

In summary, In Angular, we can enhance component interaction and control by utilizing techniques such as component communication via @ViewChild and @ViewChildren decorators to exchange data and trigger actions between parent and child components, accessing child component instances programmatically, and manipulating lifecycle hooks for fine-grained control. These approaches allow for flexible and interactive Angular applications that adapt to user interactions and changing requirements.

--

--

No responses yet