Introduction
Angular provides robust ways to access and manipulate DOM elements within components, ensuring efficient interaction between your application’s logic and its presentation layer. This guide covers various techniques for selecting and managing DOM elements using Angular’s built-in features.
Accessing DOM Elements with Template References
Using #templateVar
In Angular templates, you can create template reference variables that allow direct access to DOM elements in the component class. These are declared using the #
syntax:
<input #myInput type="text" (input)="updateName(myInput.value)">
<p>My name: {{ myName }}</p>
In your component, you can access this element by utilizing Angular’s lifecycle hook ngAfterViewInit
, which ensures that the view has been fully initialized before accessing any elements:
import { Component, ViewChild, ElementRef } from '@angular/core';
@Component({
selector: 'app-display',
template: `
<input #myInput type="text" (input)="updateName(myInput.value)">
<p>My name: {{ myName }}</p>
`
})
export class DisplayComponent {
myName: string = "Aman";
@ViewChild('myInput') inputElement!: ElementRef;
ngAfterViewInit() {
console.log(this.inputElement.nativeElement.value);
}
updateName(input: string) {
this.myName = input;
}
}
Using @ViewChild
and @ViewChildren
Decorators
The @ViewChild
decorator allows access to a single child element, directive, or component. Conversely, @ViewChildren
can be used for accessing multiple elements:
import { Component, ViewChild, ViewChildren, QueryList } from '@angular/core';
@Component({
selector: 'app-list',
template: `
<div *ngFor="let item of items; let i = index" #itemRef>{{ item }}</div>
`
})
export class ListComponent {
items = ['Item 1', 'Item 2', 'Item 3'];
@ViewChild('itemRef') singleItem!: ElementRef;
@ViewChildren('itemRef') allItems!: QueryList<ElementRef>;
ngAfterViewInit() {
console.log(this.singleItem.nativeElement.innerHTML);
this.allItems.forEach(item => console.log(item.nativeElement.innerHTML));
}
}
Direct DOM Access
Sometimes you may need direct access to the native element of a component. This can be achieved by injecting ElementRef
:
import { Component, ElementRef, OnInit } from '@angular/core';
@Component({
selector: 'app-element-access',
template: '<div>Access my div</div>'
})
export class ElementAccessComponent implements OnInit {
constructor(private elementRef: ElementRef) {}
ngOnInit() {
const nativeElement = this.elementRef.nativeElement;
console.log(nativeElement.innerHTML);
}
}
Accessing Projected Content
To interact with content projected into your component, use @ContentChild
or @ContentChildren
. These are useful for querying elements within <ng-content>
:
import { Component, ContentChild, AfterContentInit } from '@angular/core';
@Component({
selector: 'app-projected',
template: '<ng-content></ng-content>'
})
export class ProjectedComponent implements AfterContentInit {
@ContentChild('projectedItem') contentRef!: ElementRef;
ngAfterContentInit() {
console.log(this.contentRef.nativeElement.innerHTML);
}
}
Advanced DOM Manipulation with Renderer2
For more complex or platform-independent manipulations, Angular offers Renderer2
, which allows you to safely manipulate elements without directly interacting with the DOM:
import { Component, Renderer2, ElementRef } from '@angular/core';
@Component({
selector: 'app-renderer',
template: `<button #myButton>Click me</button>`
})
export class RendererComponent {
constructor(private renderer: Renderer2, private elRef: ElementRef) {}
ngAfterViewInit() {
const button = this.elRef.nativeElement.querySelector('button');
this.renderer.setStyle(button, 'background-color', 'blue');
}
}
Conclusion
Angular provides multiple ways to access and manage DOM elements within components. Whether you’re using template reference variables, decorators like @ViewChild
, or direct element references with ElementRef
and Renderer2
, Angular ensures a clean separation of concerns while facilitating dynamic interactions between your application’s logic and its UI.