Angular @ViewChildren
March 03, 2019
Angular @ViewChildren
Decorator is used to get the QueryList
of elements or directives from the view DOM. When a new child element is added or removed, the QueryList
will be updated and its changes
function will emit new value. @ViewChildren
sets the data before ngAfterViewInit
callback. @ViewChildren
has following metadata properties.
selector: Selector for querying.
read: It is used to read different token from the queried elements.
@ViewChildren
supports following selector.
1. A Component class
@ViewChildren(WriterComponent) writers: QueryList<WriterComponent>;
@ViewChildren(MessageDirective) private msgList: QueryList<MessageDirective>;
@ViewChildren('bkWriter') writers: QueryList<WriterComponent>; @ViewChildren('pname') persons: QueryList<ElementRef>;
read
metadata.
@ViewChildren(WriterComponent, { read: ElementRef }) writers: QueryList<ElementRef>; @ViewChildren(MessageDirective, {read: ViewContainerRef}) msgList: QueryList<ViewContainerRef>;
@ViewChildren
complete example with Component
, Directive
and Template Reference Variable.
Contents
Technologies Used
Find the technologies being used in our example.1. Angular 7.0.0
2. Angular CLI 7.0.3
3. TypeScript 3.1.1
4. Node.js 10.3.0
5. NPM 6.1.0
6. RxJS 6.3.3
@ViewChildren with Component
To use@ViewChildren
with Component, we need to pass Component name or template reference variable as selector to @ViewChildren
.
Suppose we have a component WriterComponent
. We can use QueryList
of WriterComponent
in any other component using @ViewChildren
.
@ViewChildren(WriterComponent) writers1: QueryList<WriterComponent>;
read
metadata. Here we will read ElementRef
from the queried elements.
@ViewChildren(WriterComponent, {read: ElementRef}) writers2: QueryList<ElementRef>;
ViewContainerRef
from the queried elements.
@ViewChildren(WriterComponent, {read: ViewContainerRef}) writers3: QueryList<ViewContainerRef>;
QueryList
inside ngAfterViewInit
method because @ViewChildren
sets the data before AfterViewInit
. Now find the complete code.
vc-demo1.component.ts
import { Component, ViewChildren, AfterViewInit, ViewContainerRef, QueryList, ElementRef } from '@angular/core'; import { WriterComponent } from './writer.component'; @Component({ selector: 'app-vc-demo1', template: ` <h3>@ViewChildren + Component</h3> <div> <writer name="Krishna" book="Angular Tutorials"></writer> <br/> <writer name="Mahesh" book="Java Tutorials"></writer> <br/> <writer name="Krishna" book="jQuery Tutorials"></writer> <br/> <writer name="Bramha" book="Hibernate Tutorials" *ngIf="allWritersVisible"></writer> <br/> <writer name="Vishnu" book="Spring Tutorials" *ngIf="allWritersVisible"></writer> </div> <button (click)="onShowAllWriters()" > <label *ngIf="!allWritersVisible">Show More</label> <label *ngIf="allWritersVisible">Show Less</label> </button> ` }) export class VCOneDemoComponent implements AfterViewInit { @ViewChildren(WriterComponent) writers1: QueryList<WriterComponent>; @ViewChildren(WriterComponent, { read: ElementRef }) writers2: QueryList<ElementRef>; @ViewChildren(WriterComponent, { read: ViewContainerRef }) writers3: QueryList<ViewContainerRef>; allWritersVisible = false; ngAfterViewInit() { console.log('--- @ViewChildren + Component ---'); this.writers1.changes.subscribe(list => { list.forEach(writer => console.log(writer.writerName + ' - ' + writer.bookName)); }); console.log(this.writers1.length); console.log("Result with ElementRef:"); this.writers2.forEach(el => console.log(el)); console.log("Result with ViewContainerRef:"); this.writers3.forEach(vref => console.log(vref)); } onShowAllWriters() { this.allWritersVisible = (this.allWritersVisible === true) ? false : true; } }
import { Component, Input } from '@angular/core'; @Component({ selector: 'writer', template: ` {{writerName}} - {{bookName}} ` }) export class WriterComponent { @Input('name') writerName: string; @Input('book') bookName: string; }
QueryList
will be changed and this change can be observed using QueryList.changes
.
We can also use template reference variable with
@ViewChildren
to obtain QueryList
of Component. Suppose we have following HTML code.
<writer name="Krishna" book="Angular Tutorials" #bkWriter></writer> <br/> <writer name="Mahesh" book="Java Tutorials" #bkWriter></writer> <br/> <writer name="Krishna" book="jQuery Tutorials" #bkWriter></writer> <br/>
bkWriter
as template reference variable for WriterComponent
. Now we will query data as following.
@ViewChildren('bkWriter') writers1: QueryList<WriterComponent>;
@ViewChildren with Directive
We will query Directive using@ViewChildren
and embed a message using createEmbeddedView
of ViewContainerRef
class.
vc-demo2.component.ts
import { Component, ViewChild, ViewChildren, AfterViewInit, ViewContainerRef, TemplateRef, QueryList } from '@angular/core'; import { MessageDirective } from './message.directive'; @Component({ selector: 'app-vc-demo2', template: ` <h3>@ViewChildren + Directive</h3> <div cpMsg></div> <div cpMsg></div> <div cpMsg></div> <ng-template #msgTemp> Hello World! </ng-template> ` }) export class VCTwoDemoComponent implements AfterViewInit { @ViewChildren(MessageDirective) private msgList: QueryList<MessageDirective>; @ViewChild('msgTemp') private msgTempRef: TemplateRef<any>; ngAfterViewInit() { console.log('--- @ViewChildren + Directive ---'); console.log("this.msgList.length: " + this.msgList.length); this.msgList.forEach(messageDirective => messageDirective.viewContainerRef.createEmbeddedView(this.msgTempRef)); } }
read
metadata to read ViewContainerRef
directly from the directive.
@ViewChildren(MessageDirective, {read: ViewContainerRef}) private msgList: QueryList<ViewContainerRef>; ngAfterViewInit() { this.msgList.forEach(vcRef => vcRef.createEmbeddedView(this.msgTempRef)); }
message.directive.ts
import { Directive, ViewContainerRef } from '@angular/core'; @Directive({ selector: '[cpMsg]' }) export class MessageDirective { constructor(public viewContainerRef: ViewContainerRef) { } }
@ViewChildren with ElementRef
We will use@ViewChildren
with ElementRef
here.
vc-demo3.component.ts
import { Component, ViewChildren, AfterViewInit, QueryList, ElementRef } from '@angular/core'; @Component({ selector: 'app-vc-demo3', template: ` <h3>@ViewChildren + ElementRef</h3> <div> <div #pname>Mohit</div> <div #pname>Anup</div> <div #pname>Nilesh</div> </div> ` }) export class VCThreeDemoComponent implements AfterViewInit { @ViewChildren('pname') persons: QueryList<ElementRef>; ngAfterViewInit() { console.log('--- @ViewChildren + ElementRef ---'); this.persons.forEach(el => console.log(el.nativeElement.innerHTML)); } }
ElementRef
.
Now find the other files used in the demo.
app.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <app-vc-demo1></app-vc-demo1> <app-vc-demo2></app-vc-demo2> <app-vc-demo3></app-vc-demo3> ` }) export class AppComponent { }
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { WriterComponent } from './writer.component'; import { VCOneDemoComponent } from './vc-demo1.component'; import { VCTwoDemoComponent } from './vc-demo2.component'; import { VCThreeDemoComponent } from './vc-demo3.component'; import { MessageDirective } from './message.directive'; @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent, WriterComponent, VCOneDemoComponent, VCTwoDemoComponent, VCThreeDemoComponent, MessageDirective ], providers: [ ], bootstrap: [ AppComponent ] }) export class AppModule { }
@ViewChild vs @ViewChildren vs @ContentChild vs @ContentChildren
@ViewChild
and @ViewChildren
query the elements from view DOM and @ContentChild
and @ContentChildren
query the elements from content DOM.
1
@ViewChild
queries a single element or directive. It will be first element or the Directive matching the selector from the view DOM. It is used as following.
@ViewChild(WriterComponent) writer: WriterComponent; @ViewChild(MessageDirective) message: MessageDirective;
@ViewChildren
is used to get the QueryList
of elements or directives from the view DOM. It is used as following.
@ViewChildren(WriterComponent) writers: QueryList<WriterComponent>; @ViewChildren(MessageDirective) private msgList: QueryList<MessageDirective>;
@ContentChild
gives the first element or directive matching the selector from the content DOM. It is used as following.
@ContentChild(BookDirective) book: BookDirective;
@ContentChildren
is used to get QueryList
of elements or directives from the content DOM. It is used as following.
@ContentChildren(BookDirective) books: QueryList<BookDirective>
Run Application
To run the application, find the steps.1. Download source code using download link given below on this page.
2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.
3. Run ng serve using command prompt.
4. Access the URL http://localhost:4200
Find the print screen of the output.

References
Angular Doc: ViewChildrenAngular 2/4 QueryList Example
Angular 2/4 @ContentChild and @ContentChildren Example