Angular QueryList Example

By Arvind Rai, February 12, 2024
This page will walk through Angular QueryList example. The QueryList is unmodifiable list of items that Angular keeps up-to-date when the state of the application changes. The ViewChildren and ContentChildren uses QueryList to store elements or directives from view DOM and content DOM respectively. We can subscribe to the changes of QueryList to get the current state of QueryList. It provides methods such as map, filter, find, forEach etc. The QueryList can contain the elements of the type directive, component, ElementRef, any etc.

QueryList is used with @ViewChildren as given below.
@ViewChildren('bkWriter') 
allWriters: QueryList<WriterComponent>; 
QueryList is used with @ContentChildren as given below.
@ContentChildren(BookDirective)
topBooks: QueryList<BookDirective>; 
Here on this page, we will create a complete example for QueryList. We will use QueryList with ViewChildren and ContentChildren in our example. We will show how to subscribe the changes of QueryList. We will also provide how to use QueryList methods with examples. Now let us discuss the complete example step-by-step.

QueryList: length, first, last

We can get the length of QueryList of current state, first element and last element as following.
@ViewChildren('bkWriter') 
allWriters: QueryList<WriterComponent>;	

let len = this.allWriters.length;
let firstEl = this.allWriters.first;
let lastEl = this.allWriters.last; 

QueryList.forEach

To iterate QueryList, it provides forEach() method.
@ViewChildren('bkWriter') 
allWriters: QueryList<WriterComponent>;	

this.allWriters.forEach(writer => console.log(writer.writerName + ' - ' + writer.bookName)); 

QueryList.changes

To listen the changes in QueryList, we can subscribe to its changes. QueryList provides changes getter property that returns the instance of Observable.
@ViewChildren('bkWriter') 
allWriters: QueryList<WriterComponent>;	

this.allWriters.changes.subscribe(list => {
    list.forEach(writer => console.log(writer.writerName + ' - ' + writer.bookName));	
}); 
In the list we will get current state of QueryList at any time.

QueryList.find

To find an element with a specific value, QueryList provides find method that returns the matching object.
@ViewChildren('bkWriter') 
allWriters: QueryList<WriterComponent>;	

let javaWriter = this.allWriters.find(writer => writer.bookName === 'Java Tutorials'); 

QueryList.map

To map the elements of a QueryList, it provides map method that returns an array of mapped elements.
@ViewChildren('bkWriter') 
allWriters: QueryList<WriterComponent>;	

let wnames = this.allWriters.map(writer => writer.writerName); 

QueryList.filter

To filter a QueryList, it provides filter method that returns an array of elements matching the filter condition.
@ViewChildren('bkWriter') 
allWriters: QueryList<WriterComponent>;	

let writers = this.allWriters.filter(writer => writer.writerName === 'Krishna'); 

QueryList + @ViewChildren Example

Find the example of QueryList with @ViewChildren decorator.
@ViewChildren('bkWriter') 
allWriters: QueryList<WriterComponent>; 
@ViewChildren gets the list of elements or directives from the view DOM as QueryList.
cp1.component.ts
import { Component, ViewChild, ViewChildren, AfterViewInit, TemplateRef, ViewContainerRef, QueryList, ElementRef } from '@angular/core';
import { MessageDirective } from './message.directive';
import { WriterComponent } from './writer.component';

@Component({
	selector: 'app-cp1',
	templateUrl: './cp1.component.html'
})
export class Cp1Component implements AfterViewInit {
	//QueryList + @ViewChildren + Directive
	@ViewChildren(MessageDirective)
	private msgList = {} as QueryList<MessageDirective>;

	@ViewChild('msgTemp')
	private msgTempRef = {} as TemplateRef<any>;

	//QueryList + @ViewChildren + Component
	@ViewChildren('bkWriter')
	allWriters = {} as QueryList<WriterComponent>;

	showAllWriter = false;

	//QueryList + @ViewChildren + ElementRef
	@ViewChildren('pname')
	allPersons = {} as QueryList<ElementRef>;

	ngAfterViewInit() {
		console.log('--- using QueryList.changes ---');
		this.allWriters.changes.subscribe(list => {
			list.forEach((writer: WriterComponent) => console.log(writer.writerName + ' - ' + writer.bookName));
		});
		console.log('--- using QueryList.forEach ---');
		this.msgList.forEach(messageDirective =>
			messageDirective.viewContainerRef.createEmbeddedView(this.msgTempRef));

		this.allWriters.forEach(writer => console.log(writer.writerName + ' - ' + writer.bookName));

		console.log('--- using QueryList.length ---');
		console.log(this.allWriters.length);

		console.log('--- using QueryList.find ---');
		let javaWriter = this.allWriters.find(writer => writer.bookName === 'Java Tutorials');
		console.log(javaWriter?.writerName);

		console.log('--- using QueryList.map ---');
		let wnames = this.allWriters.map(writer => writer.writerName);
		for (let name of wnames) {
			console.log(name);
		}

		console.log('--- using QueryList.filter ---');
		let writers = this.allWriters.filter(writer => writer.writerName === 'Krishna');
		for (let w of writers) {
			console.log(w.bookName);
		}

		console.log('--- using QueryList.first ---');
		let firstEl = this.allPersons.first;
		console.log(firstEl.nativeElement.innerHTML);

		console.log('--- using QueryList.last ---');
		let lastEl = this.allPersons.last;
		console.log(lastEl.nativeElement.innerHTML);
	}
	onShowAllWriters() {
		this.showAllWriter = (this.showAllWriter === true) ? false : true;
	}
} 
cp1.component.html
<h3>QueryList + @ViewChildren + Directive</h3>
<ng-template #msgTemp>
   Welcome to you.<br/>
   Happy learning!
</ng-template>
<div cpMsg> </div>
<div cpMsg> </div>

<h3>QueryList + @ViewChildren + ElementRef</h3>
<div>
  <div #pname>Mohit</div>
  <div #pname>Anup</div>
  <div #pname>Nilesh</div>
</div>

<h3>QueryList + @ViewChildren + Component</h3>
<div>
  <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/>
  <writer name="Bramha" book="Hibernate Tutorials" #bkWriter *ngIf="showAllWriter"></writer> <br/>   
  <writer name="Vishnu" book="Spring Tutorials" #bkWriter *ngIf="showAllWriter"></writer>  
</div>
<button (click)="onShowAllWriters()" >
  <label *ngIf="!showAllWriter">Show More</label>
  <label *ngIf="showAllWriter">Show Less</label>
</button> 
writer.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'writer',
  template: `
       {{writerName}} - {{bookName}}
  `
})
export class WriterComponent {
	@Input('name') writerName = '';
	@Input('book') bookName = '';
} 
message.directive.ts
import { Directive, ViewContainerRef } from '@angular/core';

@Directive({ 
   selector: '[cpMsg]' 
})
export class MessageDirective {
   constructor(public viewContainerRef: ViewContainerRef) { }
} 


QueryList + @ContentChildren Example

Find the example of QueryList with @ContentChildren decorator.
@ContentChildren(BookDirective)
topBooks: QueryList<BookDirective>; 
@ContentChildren gets the list of elements or directives from the content DOM as QueryList.
cp2.component.ts
import { Component } from '@angular/core';

@Component({
   selector: 'app-cp2',
   templateUrl: './cp2.component.html'
})
export class Cp2Component {
   showAllBook = false;
   onShowAllBooks() {
	this.showAllBook = (this.showAllBook === true)? false : true;
   }     
} 
cp2.component.html
<h3>QueryList + @ContentChildren + Directive</h3>
<favourite-books>
	<book bookId="1" bookName="Hibernate 4 Tutorials"></book>
	<book bookId="2" bookName="Spring Boot Tutorials"></book>
	<favourite-books>
	   <book bookId="3" bookName="Learning JavaScript"></book>
	</favourite-books>   
	<favourite-books *ngIf="showAllBook">
	   <book bookId="4" bookName="Thymeleaf Tutorials"></book>
	   <book bookId="5" bookName="Android Tutorials"></book>
	</favourite-books>   
</favourite-books>
<br/>
<button (click)="onShowAllBooks()" >
  <label *ngIf="!showAllBook">Show More</label>
  <label *ngIf="showAllBook">Show Less</label>
</button>	

<h3>QueryList + @ContentChildren + ElementRef</h3>
<favourite-friends>
	<div #ffname>Mohit</div>
	<div #ffname>Anup</div>
        <div #ffname>Nilesh</div>
</favourite-friends> 
book.directive.ts
import { Directive, Input } from '@angular/core';

@Directive({
    selector: 'book'
})
export class BookDirective {
	@Input() bookId = '';
	@Input() bookName = '';
} 
favourite-books.component.ts
import { Component, ContentChildren, QueryList, AfterContentInit } from '@angular/core';
import { BookDirective } from './book.directive';

@Component({
	selector: 'favourite-books',
	template: `
    <b>Top Favourite Books</b>
	<ng-template ngFor let-book [ngForOf]= "topBooks">
	   <br/>{{book.bookId}} - {{book.bookName}}
	</ng-template>
		
	<br/><b>All Favorite Books</b>
	<ng-template ngFor let-book [ngForOf]= "allBooks">
	   <br/>{{book.bookId}} - {{book.bookName}}
	</ng-template>	
  `
})
export class FavouriteBooksComponent implements AfterContentInit {
	//QueryList + @ContentChildren + Directive
	@ContentChildren(BookDirective)
	topBooks = {} as QueryList<BookDirective>;

	@ContentChildren(BookDirective, { descendants: true })
	allBooks = {} as QueryList<BookDirective>;

	ngAfterContentInit() {
		console.log('---Book details---');
		this.topBooks.forEach(book => console.log(book.bookId + " - " + book.bookName));
	}
} 
favourite-friends.component.ts
import { Component, ContentChildren, QueryList, ElementRef, AfterContentInit } from '@angular/core';

@Component({
	selector: 'favourite-friends',
	template: `
	   {{allFriends}}	
  `
})
export class FavouriteFriendsComponent implements AfterContentInit {
	//QueryList + @ContentChildren + ElementRef
	@ContentChildren('ffname')
	allFriendsRef = {} as QueryList<ElementRef>;

	get allFriends(): string {
		return this.allFriendsRef ? this.allFriendsRef.map(f => f.nativeElement.innerHTML).join(', ') : '';
	}
	ngAfterContentInit() {
		console.log(this.allFriends);
	}
} 

Output

Find the print-screen of the output.
Angular QueryList Example

Reference

QueryList

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us