Using ViewChild with Directives
What is a Directive in Angular?
Directives in Angular are classes that add behavior to elements in your Angular applications. For example, built-in directives like ngIf and ngFor manipulate DOM elements based on conditions or data.
With ViewChild, you can access elements that are tied to custom directives in your templates.
Example: Accessing a Custom Directive
Suppose we have a custom directive called HighlightDirective that highlights an element when applied. Here's how to use ViewChild to access and interact with it:
Step 1: Create a Custom Directive
import { Directive, ElementRef, Renderer2 } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(private el: ElementRef, private renderer: Renderer2) {}
highlight(color: string) {
this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', color);
}
}
Step 2: Use the Directive in a Template
<p appHighlight>
Hover over me to see the magic!
</p>
<button (click)="applyHighlight()">Highlight Text</button>
Step 3: Access the Directive with ViewChild
import { Component, ViewChild } from '@angular/core';
import { HighlightDirective } from './highlight.directive';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
@ViewChild(HighlightDirective) highlightDirective!: HighlightDirective;
applyHighlight() {
this.highlightDirective.highlight('yellow');
}
}
Explanation:
- The @ViewChild decorator links the HighlightDirective instance.
- The applyHighlight() method uses the directive to change the background color.
Using ViewChild with DOM Elements
What are DOM Elements?
DOM (Document Object Model) elements are the building blocks of a webpage. You can manipulate these elements in Angular using ViewChild.
Example: Accessing and Modifying DOM Elements
Step 1: Define the Template
<input #inputBox type="text" placeholder="Type something" />
<button (click)="changeText()">Change Text</button>
Step 2: Use ViewChild to Access the Element
import { Component, ViewChild, ElementRef } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
@ViewChild('inputBox') inputBox!: ElementRef;
changeText() {
this.inputBox.nativeElement.value = 'Hello, Angular!';
}
}
Explanation:
- The #inputBox template reference variable identifies the input element.
- The @ViewChild('inputBox') decorator captures the input element and stores it in the inputBox property.
- The changeText() method updates the value of the input element directly.
Output:
When you click the button, the text in the input box changes to "Hello, Angular!"
Using ViewChild with Child Components
What is a Child Component in Angular?
A child component is a reusable block of UI in Angular that is nested inside another component.
Example: Communicating with a Child Component
Let's create a parent component that interacts with a child component using ViewChild.
Step 1: Define the Child Component
import { Component } from '@angular/core';
@Component({
selector: 'app-child',
template: `<p>{{message}}</p>`,
})
export class ChildComponent {
message: string = 'Hello from Child Component!';
updateMessage(newMessage: string) {
this.message = newMessage;
}
}
Step 2: Use the Child Component in a Parent Template
<app-child></app-child>
<button (click)="updateChild()">Update Child Message</button>
Step 3: Access the Child Component with ViewChild
import { Component, ViewChild } from '@angular/core';
import { ChildComponent } from './child.component';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
@ViewChild(ChildComponent) childComponent!: ChildComponent;
updateChild() {
this.childComponent.updateMessage('Message Updated by Parent Component!');
}
}
Explanation:
- The ChildComponent has a method updateMessage() to change its message property.
- The parent component uses @ViewChild(ChildComponent) to interact with the child component.
- Clicking the button triggers the updateChild() method to modify the child’s message.
Output:
Initially, the child displays: "Hello from Child Component!"
After clicking the button: "Message Updated by Parent Component!"
How to Use ViewChild with TemplateRef and ViewContainerRef
Here’s a step-by-step example to demonstrate how you can use ViewChild with TemplateRef and ViewContainerRef:
1. Define a Template in Your Component’s HTML
First, create a template using the `<ng-template>` directive in your component’s HTML file.
<ng-template #myTemplate>
<p>This is a dynamically rendered template!</p>
</ng-template>
Here, `#myTemplate` is a template reference variable that we’ll use to access this template in our TypeScript code.
2. Access the Template Using ViewChild
In your component’s TypeScript file, use the ViewChild decorator to access the template.
import { Component, ViewChild, TemplateRef, ViewContainerRef } from '@angular/core';
@Component({
selector: 'app-dynamic-view',
templateUrl: './dynamic-view.component.html',
})
export class DynamicViewComponent {
@ViewChild('myTemplate', { read: TemplateRef }) myTemplate!: TemplateRef<any>;
constructor(private viewContainerRef: ViewContainerRef) {}
ngAfterViewInit() {
// Render the template dynamically
this.viewContainerRef.createEmbeddedView(this.myTemplate);
}
}
- `@ViewChild('myTemplate', { read: TemplateRef })` accesses the template defined in the HTML.
- `ViewContainerRef` is injected into the constructor to provide a container for the template.
- In `ngAfterViewInit`, the `createEmbeddedView` method is used to render the template dynamically.
3. Result
When the component is rendered, the content inside the `<ng-template>` will be dynamically added to the DOM.
Practical Use Cases
- Dynamic Component Loading: You can use this approach to load components dynamically based on user interactions.
- Conditional Rendering: Render templates conditionally without cluttering your HTML with `*ngIf` statements.
This combination of ViewChild, TemplateRef, and ViewContainerRef is a powerful way to manage dynamic content in Angular applications.
What is QueryList?
QueryList is a collection of items that Angular keeps updated automatically. It’s often used with ViewChildren or ContentChildren decorators to access multiple child elements or components. Unlike ViewChild, which accesses a single element, QueryList allows you to work with a dynamic list of items.
Usage of QueryList
In Angular, QueryList is a class that provides a way to manage a list of child elements, components, or directives. It’s particularly useful when you need to work with multiple instances of a child element or component. Let’s explore how QueryList works and how you can use it effectively.
How to Use QueryList with ViewChildren
Let’s look at a step-by-step example to see how you can use QueryList with ViewChildren:
1. Define Multiple Child Elements in Your Component’s HTML
Let’s say you have a list of child elements in your component’s HTML file.
<div #myElement>First Element</div>
<div #myElement>Second Element</div>
<div #myElement>Third Element</div>
Here, `#myElement` is a template reference variable used to identify each child element.
2. Access the Child Elements Using ViewChildren
In your component’s TypeScript file, use the ViewChildren decorator to access all the child elements.
import { Component, ViewChildren, QueryList, ElementRef, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-multiple-elements',
templateUrl: './multiple-elements.component.html',
})
export class MultipleElementsComponent implements AfterViewInit {
@ViewChildren('myElement') myElements!: QueryList<ElementRef>;
ngAfterViewInit() {
// Log the number of child elements
console.log('Number of elements:', this.myElements.length);
// Iterate through the list of elements
this.myElements.forEach((element, index) => {
console.log(`Element ${index}:`, element.nativeElement.textContent);
});
}
}
- `@ViewChildren('myElement')` accesses all the child elements with the template reference variable `#myElement`.
- `QueryList<ElementRef>` is a collection of ElementRef objects, each representing a child element.
- In `ngAfterViewInit`, you can iterate through the QueryList to access each element’s properties or perform actions.
3. Result
When the component is rendered, the QueryList will contain all the child elements with the reference `#myElement`. You can then manipulate or interact with these elements dynamically.
Practical Use Cases
- Dynamic Lists: Manage lists of elements or components that are added or removed dynamically.
- Component Interaction: Access multiple instances of a child component to call methods or update properties.
- DOM Manipulation: Perform actions like adding styles or event listeners to multiple elements.
Key Features of QueryList
- Dynamic Updates: QueryList automatically updates when child elements are added or removed.
- Iterable: You can use methods like `forEach`, `map`, or `filter` to work with the list of items.
- Change Detection: QueryList provides a `changes` observable that notifies you when the list is updated.
Let’s look at an example of using the `changes` observable:
ngAfterViewInit() {
this.myElements.changes.subscribe((elements: QueryList<ElementRef>) => {
console.log('List of elements updated:', elements.length);
});
}
This allows you to react to changes in the list of child elements dynamically.
Frequently Asked Questions
What is the main use of the ViewChild decorator?
The ViewChild decorator is used to access and manipulate template elements, directives, or child components in an Angular application.
Can ViewChild be used with multiple elements?
No, ViewChild is used to select a single element. To select multiple elements, use the ViewChildren decorator.
How do you handle errors when the ViewChild element is not found?
You can use the static property in @ViewChild and set it to false to ensure it resolves only after the view is initialized.
Conclusion
The ViewChild decorator is a powerful feature in Angular that simplifies interaction within templates. By using ViewChild, you can easily access and manipulate directives, DOM elements, and child components, making your application more dynamic and responsive. Whether you’re customizing UI behavior, modifying DOM properties, or enabling seamless communication between parent and child components, ViewChild is an essential tool for Angular developers.
You can also check out our other blogs on Code360.