Angular ViewChild and ViewChildren decorator allow us to access and manipulate HTML elements in DOM or the child component by parent component. Angular provides different ways of communication between components.
Components can query the content of their templates to locate instances of element/directive/component, which are known as view children. Angular viewChildren decorator declares a reference to multiple child elements of the same type in DOM to query in the parent component. Angular viewChildren() decorator works similarly to @ViewChild, except use ViewChild() decorator if we need to query one element from the DOM.
When to use Angular viewChildren decorator?
What happens if there is more than one directive/component/element of the same type defined on the component view? Use the @ViewChildren decorator. It allows you to query injections with a reference to one type of element or component. We can use this reference in the component class to manipulate its value and properties.
The syntax for angular ViewChildren
@ViewChildren(directiveType) children: QueryList;
This injects a reference to all the view children of type directive type. When you declare your instance variable, you specify a selector in parentheses, which is used to bind all children elements of the same type which we want to query and access in class. This selector can be the child type (that is, the class of the Child Angular element) or the template reference.
Example of Angular viewChildren decorator to inject a reference to native DOM element
In the example below, we can use the ViewChildren decorator to inject a reference to all h2 tags in the template, access, and change the h2 tag color to green in a class of app.component.ts file.
import { Component, ViewChildren, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<div>
<h2 #heading>Angular Framwork</h2>
<p>Angular is a TypeScript-based open-source web application framework led by the Angular Team at Google ....
</p>
</div>
<div>
<h2 #heading>React Framwork</h2>
<p>React is a JavaScript library for building user interfaces. It is maintained by Facebook and a community ...
</p>
</div>
<h4 *ngIf="total"> {{ total }} </h4>
`,
styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {
@ViewChildren('heading') headings;
total = '';
ngAfterViewInit() {
setTimeout(() => {
this.total = 'Number of h1 tag : ' + this.headings.length;
this.headings.forEach(element => {
element.nativeElement.style.color = 'green';
});
});
}
}
Properties decorated with @ViewChild and @ViewChildren are sure to be set before the ngAfterViewInit event hook on the component is called. This implies such properties are null if accessed inside the constructor.
The reference to a @ViewChildren variable is assigned once the View has been initialized. We can only access it once the View is initialized and rendered, the @ViewChild and @ViewChildren can then access the element using the template reference.
Example of Angular ViewChildren decorator to inject a reference to multiple child components of the same type in the parent component.
An Angular allows us to inject a reference to the multiple child components, in our case we have (QuoteComponent) into the parent Component. The search is done based on the selector passed to the @ViewChildren() decorator.
We have to create an Angular project and create a child component quote
$ng new viewChildrenApp
$ng generate component quote
In the app.component.ts class, we have ngFor directive to loop on the list of quotes, we are using child component quote to display quote detail.
import { QuoteComponent } from './quote/quote.component';
import { Component, ViewChildren, QueryList, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<div>
Parent component
<div class="child-component">
<h3>Child component list of quote component</h3>
<app-quote *ngFor="let quoteData of quotes" [quote]="quoteData" #quoteRef></app-quote>
</div>
</div>
`,
styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {
@ViewChildren('quoteRef') quoteComponent: QueryList<QuoteComponent>;
quotes = [
{ data: 'All philosophies are mental fabrications. There has never been a single doctrine by which one could enter the true essence of things.', by: 'Acharya Nagarjuna'},
{ data: 'Believe nothing, no matter where you read it, or who said it, no matter if I have said it, unless it agrees with your own reason and your own common sense.', by: 'Buddha'},
{ data: 'Remember that sometimes not getting what you want is a wonderful stroke of luck.', by: 'Dalai Lama XIV'}
];
ngAfterViewInit() {
const quoteData: any = this.quoteComponent.toArray()[0];
console.log('Quote 1st : ' + quoteData.quote.data);
setTimeout(() => {
this.quoteComponent.forEach((quoteData, index) => {
console.log(quoteData, index);
if (index === 2) {
quoteData.quote.by = 'DALAI LAMA';
}
});
});
}
}
In the child component quote is used to display quote details and we will get it to quote detail data from the parent component by Input() decorate. In the quote.component.ts file, we have
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-quote',
template: `
<p>
{{ quote.data }}
<strong>By: {{ quote.by }}</strong>
</p>
`,
styleUrls: ['./quote.component.scss']
})
export class QuoteComponent {
@Input() quote: { data: string, by: string };
}
Angular ViewChildren() decorator allow us to get a reference to a list of child component and we can use this reference to query, access, and manipulate child component property in the parent component.
Angular ViewChildren decorator returns a list called QueryList
The data type of the variable children is not an array, but a custom class- QueryList. The QueryList class is not a typical array, but it’s iterable in the sense you could use it in a loop as QueryList class implements the interface Iterable.
It also has an observable to which we can subscribe to it and get notified by Angular when the content changes.
Class QueryList<T> implements Iterable {
changes: Observable<any>;
.....
}
With a reference to multiple components/directives/elements. We can add/remove child elements or move, the query list will be updated, and the changes observable of the query list will emit a new value.
The QueryList is an unmodifiable list of items that Angular keeps up to date when the state of the application changes. The QueryList return object contains the following properties:
- First returns the first element matching the query
- Last returns the last element matching the query
- Length returns how many elements are matching the query
- Changes return an observable that will emit the new QueryList every time an element matching the query is added, removed, or moved
- The result returns an array containing a list of all elements in Querylist.
More information and check on @viewChildren decoration from the angular official documentation.
Related Post
- Angular ViewChildren decorator in details
- How to implement Angular ViewChild Decorator
- What is Angular ElementRef ?