What Are Components in Angular
What Are Components in Angular
@Component({
selector: 'app-parent',
template: `
<app-child [childMessage]="parentMessage"></app-child>
`,
styleUrls: ['./parent.component.css']
})
constructor() { }
}
parent.component.ts
Add bellow code in child.component.ts file :
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: ` Say {{ message } `,
styleUrls: ['./child.component.css']
})
child.component.ts
2. Child to Parent: Sharing Data via ViewChild with AfterViewInit
ViewChild allows a child component to be injected into a parent component.
It will give the parent access to its attributes and functions.
A Child won’t be available to give access until the view has been initialized.
This means we need to implement the AfterViewInit lifecycle hook to receive the data from the child.
Add bellow code in parent.component.ts file :
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from "../child/child.component";
@Component({
selector: 'app-parent',
template: `
Message: {{ message }}
<app-child></app-child>
`,
styleUrls: ['./parent.component.css']
})
@ViewChild(ChildComponent) child;
constructor() { }
Message:string;
ngAfterViewInit() {
this.message = this.child.message
}
}
parent.component.ts
Add bellow code in child.component.ts
import { Component} from '@angular/core';
@Component({
selector: 'app-child',
template: ` `,
styleUrls: ['./child.component.css']
})
constructor() { }
}
child.component.ts
3. Child to Parent: Sharing Data via Output() and EventEmitter
Another way to share data is to emit data from the child component which can be listed by the parent component.
This approach is ideal when you want to share data changes that occur on things like button clicks, form entries, and
other user events.
For e.g.
In the parent, we create a function to receive the message and set it equal to the message variable.
In the child, we declare a messageEvent variable with the Output decorator and set it equal to a new event emitter.
Then we create a function named sendMessage that calls emit on this event with the message we want to send.
Lastly, we create a button to trigger this function.
The parent can now subscribe to this messageEvent that’s outputted by the child component, then run the receive
message function whenever this event occurs.
Add bellow code in parent.component.ts file :
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
template: `
Message: {{message}}
<app-child (messageEvent)="receiveMessage($event)"></app-child>
`,
styleUrls: ['./parent.component.css']
})
constructor() { }
Message:string;
receiveMessage($event) {
this.message = $event
}
}
parent.component.ts
Add bellow code in child.component.ts file :
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
template: `
<button (click)="sendMessage()">Send Message</button>
`,
styleUrls: ['./child.component.css']
})
constructor() { }
sendMessage() {
this.messageEvent.emit(this.message)
}
}
child.component.ts
#Conclusion
Here we define how to share data between component in Angular 8
We can share data from parent to child via @Input
We can share data from child to parent via ViewChild
We can share data from child to parent via @Output for button clicks or Form entries
What are Subjects ?
A Subject is a special type of Observable that allows values to be multicasted to many Observers. The subjects are
also observers because they can subscribe to another observable and get value from it, which it will multicast to all
of its subscribers.
Basically, a subject can act as both observable & an observer.
How does Subjects work
Subjects implement both subscribe method and next, error & complete methods. It also maintains a collection
of observers[]
An Observer can subscribe to the Subject and receive value from it. Subject adds them to its collection observers.
Whenever there is a value in the stream it notifies all of its Observers.
The Subject also implements the next, error & complete methods. Hence it can subscribe to another observable and
receive values from it.
Creating a Subject in Angular
The following code shows how to create a subject in Angular.
app.component.ts
1
2 import { Component, VERSION } from "@angular/core";
3 import { Subject } from "rxjs";
4
5 @Component({
6 selector: "my-app",
7 templateUrl: "./app.component.html",
8 styleUrls: ["./app.component.css"]
9 })
10 export class AppComponent {
11
12 subject$ = new Subject();
13
14 ngOnInit() {
15
16 this.subject$.subscribe(val => {
17 console.log(val);
18 });
19
20 this.subject$.next("1");
21 this.subject$.next("2");
22 this.subject$.complete();
23 }
24 }
25
Stackblitz
The code that creates a subject.
1
2 subject$ = new Subject();
3
We subscribe to it just like any other observable.
1
2 this.subject$.subscribe(val => {
3 console.log(val);
4 });
5
The subjects can emit values. You can use the next method to emit the value to its subscribers. Call
the complete & error method to raise complete & error notifications.
1
2 this.subject$.next("1");
3 this.subject$.next("2");
4 this.subject$.complete();
5 //this.subject$.error("error")
6
That’s it.
Subject is an Observable
The subject is observable. It must have the ability to emit a stream of values
The previous example shows, we can use the next method to emit values into the stream.
1
2 this.subject$.next("1");
3 this.subject$.next("2");
4
Subject is hot Observable
Observables are classified into two groups. Cold & Hot
Cold observable
The cold observable does not activate the producer until there is a subscriber. This is usually the case when the
observable itself produces the data.
1
2 import { Component, VERSION } from "@angular/core";
3 import { Subject, of } from "rxjs";
4
5 import { Component, VERSION } from "@angular/core";
6 import { Observable, of } from "rxjs";
7
8 @Component({
9 selector: "my-app",
10 templateUrl: "./app.component.html",
11 styleUrls: ["./app.component.css"]
12 })
13 export class AppComponent {
14 obs1$ = of(1, 2, 3, 4);
15
16 obs$ = new Observable(observer => {
17 console.log("Observable starts");
18 observer.next("1");
19 observer.next("2");
20 observer.next("3");
21 observer.next("4");
22 observer.next("5");
23 });
24
25 ngOnInit() {
26 this.obs$.subscribe(val => {
27 console.log(val);
28 });
29 }
30 }
31
32
Stackblitz
The Producer is one that produces the data. In the above example above it is part of the observable itself. We cannot
use that to emit data ourselves.
ReplaySubject, BehaviorSubject & AsyncSubject are special types of subjects in Angular. In this tutorial let us learn
what are they, how they work & how to use them in Angular
00:02/03:27
Table of Contents
BehaviorSubject
ReplaySubject
AsyncSubject
Reference
BehaviorSubject
BehaviorSubject requires an initial value and stores the current value and emits it to the new subscribers.
1
2 import { Component, VERSION } from "@angular/core";
3 import { BehaviorSubject, Subject } from "rxjs";
4
5 @Component({
6 selector: "my-app",
7 templateUrl: "./app.component.html",
8 styleUrls: ["./app.component.css"]
9 })
10 export class AppComponent {
11 subject$ = new BehaviorSubject("0");
12
13 ngOnInit() {
14 this.subject$.subscribe(val => {
15 console.log("Sub1 " + val);
16 });
17
18 this.subject$.next("1");
19 this.subject$.next("2");
20
21 this.subject$.subscribe(val => {
22 console.log("sub2 " + val);
23 });
24
25 this.subject$.next("3");
26 this.subject$.complete();
27 }
28 }
29
30
31
32 ***Result***
33
34 Sub1 0
35 Sub1 1
36 Sub1 2
37 sub2 2
38 Sub1 3
39 sub2 3
40
41
StackBlitz
We create a new BehaviorSubject providing it an initial value or seed value. The BehaviorSubject stores the initial
value.
1
2 subject$ = new BehaviorSubject("0");
3
As soon as the first subscriber subscribes to it, the BehaviorSubject emits the stored value. i.e. 0
1
2 this.subject$.subscribe(val => {
3 console.log("Sub1 " + val);
4 });
5
We emit two more values. The BehaviorSubject stores the last value emitted i.e. 2
1
2 this.subject$.next("1");
3 this.subject$.next("2");
4
Now, Subscriber2 subscribes to it. It immediately receives the last value stored i.e. 2
1
2 this.subject$.subscribe(val => {
3 console.log("sub2 " + val);
4 });
5
ReplaySubject
ReplaySubject replays old values to new subscribers when they first subscribe.
The ReplaySubject will store every value it emits in a buffer. It will emit them to the new subscribers in the order it
received them. You can configure the buffer using the arguments bufferSize and windowTime
bufferSize: No of items that ReplaySubject will keep in its buffer. It defaults to infinity.
windowTime: The amount of time to keep the value in the buffer. Defaults to infinity.
Example
1
2
3 import { Component, VERSION } from "@angular/core";
4 import { ReplaySubject, Subject } from "rxjs";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12 subject$ = new ReplaySubject();
13
14 ngOnInit() {
15 this.subject$.next("1");
16 this.subject$.next("2");
17
18 this.subject$.subscribe(
19 val => console.log("Sub1 " + val),
20 err => console.error("Sub1 " + err),
21 () => console.log("Sub1 Complete")
22 );
23
24 this.subject$.next("3");
25 this.subject$.next("4");
26
27 this.subject$.subscribe(val => {
28 console.log("sub2 " + val);
29 });
30
31 this.subject$.next("5");
32 this.subject$.complete();
33
34 this.subject$.error("err");
35 this.subject$.next("6");
36
37 this.subject$.subscribe(
38 val => {
39 console.log("sub3 " + val);
40 },
41 err => console.error("sub3 " + err),
42 () => console.log("Complete")
43 );
44 }
45 }
46
47 ***Result***
48 Sub1 1
49 Sub1 2
50 Sub1 3
51 Sub1 4
52 sub2 1
53 sub2 2
54 sub2 3
55 sub2 4
56 Sub1 5
57 sub2 5
58 Sub1 Complete
59 sub3 1
60 sub3 2
61 sub3 3
62 sub3 4
63 sub3 5
64 sub3 err
65
Stackblitz
First, we create a ReplaySubject
1
2 subject$ = new ReplaySubject();
3
ReplaySubject emits two values. It will also store these in a buffer.
1
2 this.subject$.next("1");
3 this.subject$.next("2");
4
We subscribe to it. The observer will receive 1 & 2 from the buffer
1
2 this.subject$.subscribe(
3 val => console.log("Sub1 " + val),
4 err => console.error("Sub1 " + err),
5 () => console.log("Sub1 Complete")
6 );
7
We subscribe again after emitting two more values. The new subscriber will also receive all the previous values.
1
2 this.subject$.next("3");
3 this.subject$.next("4");
4
5 this.subject$.subscribe(val => {
6 console.log("sub2 " + val);
7 });
8
We emit one more value & complete. All the subscribers will receive complete. They will not receive any further
values or notifcations.
1
2 this.subject$.next("5");
3 this.subject$.complete();
4
5
We now fire an error notification and a value. None of the previous subscribers will receive this as they are already
closed.
1
2 this.subject$.error("err");
3 this.subject$.next("6");
4
Now, we subscribe again. The subscriber will receive all the values up to Complete. But will not receive
the Complete notification, instead, it will receive the Error notification.
1
2 this.subject$.subscribe(
3 val => {
4 console.log("sub3 " + val);
5 },
6 err => console.error("sub3 " + err),
7 () => console.log("Complete")
8 );
9
AsyncSubject
AsyncSubject only emits the latest value only when it completes. If it errors out then it will emit an error, but will not
emit any values.
1
2 import { Component, VERSION } from "@angular/core";
3 import { AsyncSubject, Subject } from "rxjs";
4
5 @Component({
6 selector: "my-app",
7 templateUrl: "./app.component.html",
8 styleUrls: ["./app.component.css"]
9 })
10 export class AppComponent {
11 subject$ = new AsyncSubject();
12
13 ngOnInit() {
14 this.subject$.next("1");
15 this.subject$.next("2");
16
17 this.subject$.subscribe(
18 val => console.log("Sub1 " + val),
19 err => console.error("Sub1 " + err),
20 () => console.log("Sub1 Complete")
21 );
22
23 this.subject$.next("3");
24 this.subject$.next("4");
25
26 this.subject$.subscribe(val => {
27 console.log("sub2 " + val);
28 });
29
30 this.subject$.next("5");
31 this.subject$.complete();
32
33 this.subject$.error("err");
34
35 this.subject$.next("6");
36
37 this.subject$.subscribe(
38 val => console.log("Sub3 " + val),
39 err => console.error("sub3 " + err),
40 () => console.log("Sub3 Complete")
41 );
42 }
43 }
44
45
46 **Result **
47 Sub1 5
48 sub2 5
49 Sub1 Complete
50 Sub3 5
51 Sub3 Complete
52
Stackblitz
In the above example, all the subscribers will receive the value 5 including those who subscribe after the complete
event.
But if the AsyncSubject errors out, then all subscribers will receive an error notification and no value.
Angular Observable Subject Example Sharing Data Between Components
Leave a Comment / 4 minutes of reading / May 8, 2021
ReplaySubject, BehaviorSubject & AsyncSubject
Angular Global Styles
In this tutorial, we will show you how to use Subjects in Angular with examples. We learned What is Subjects in
Angular and different types of subjects like ReplaySubject, BehaviorSubject & AsyncSubject in Angular
Table of Contents
Angular Subject Example
Todo Service Using BehaviorSubject
TodoList Component
TodoAdd Component
References
Angular Subject Example
We will build a todo app. Our app has two components.
One is the Todo list component, which displays the list of todos. It also has the option to delete a todo
Another one is Todo add a component, which allows us to add a Todo item.
Both will communicate with each other via Service. Whenever a new todo is added, the service will notify the Todo
list component to update the lists using a observable
Code is available at StackBlitz
Todo Service Using BehaviorSubject
Create the todo.service.ts in the src\app folder.
todo.service.ts
1
2 import { Injectable } from "@angular/core";
3 import { BehaviorSubject } from "rxjs";
4
5 export interface Todo {
6 id: any;
7 value: string;
8 }
9
10 @Injectable()
11 export class TodoService {
12
13 private _todo = new BehaviorSubject<Todo[]>([]);
14 readonly todos$ = this._todo.asObservable();
15
16 private todos: Todo[] = [];
17 private nextId = 0;
18
19 constructor() {}
20
21 loadAll() {
22 this.todos = [];
23 this._todo.next(this.todos);
24 }
25
26 create(item: Todo) {
27 item.id = ++this.nextId;
28 this.todos.push(item);
29 this._todo.next(Object.assign([], this.todos));
30 }
31
32 remove(id: number) {
33 this.todos.forEach((t, i) => {
34 if (t.id === id) {
35 this.todos.splice(i, 1);
36 }
37 this._todo.next(Object.assign([], this.todos));
38 });
39 }
40 }
41
42
Here, we create BehaviorSubject of type Todo[]. Behavior expects us to provide an initial value. We assign an empty
array. The BehaviorSubject will always emit the latest list of Todo items as an array. We can also use Subject here.
But the advantage of BehaviorSubject is that the late subscribers will always receive the latest list of Todo items
immediately on the subscription. We do not have to call the next method.
1
2 private _todo$ = new BehaviorSubject<Todo[]>([]);
3
4
Also, it is advisable not to expose the BehaviorSubject outside the service. Hence we convert it to
normal Observable and return it. This is because the methods like next, complete or error do not exist on normal
observable. It will ensure that the end-user will not accidentally call them and mess up with it
1
2 readonly todos$ = this._todo.asObservable();
3
The todos will store the todo items in memory. We use the nextId to create the id of the Todo item.
1
2 private todos: Todo[] = [];
3 private nextId = 0;
4
Create pushes the new item to the todos list. Here we use the next method to push the todos list to all the
subscribers. Note that we use the Object.assign to create a new copy of the todos and push it to the subscribers. This
will protect our original copy of the todos list from accidental modification by the user.
1
2 create(item: Todo) {
3 item.id = ++this.nextId;
4
5 //Update database
6 this.todos.push(item);
7 this._todo$.next(Object.assign([], this.todos));
8 }
9
Remove method removes the Todo item based on id and pushes the new list to subscribers.
1
2 remove(id: number) {
3 this.todos.forEach((t, i) => {
4 if (t.id === id) {
5 this.todos.splice(i, 1);
6 }
7 this._todo$.next(Object.assign([], this.todos));
8 });
9 }
10
TodoList Component
TodoListComponent displays the list of Todo items.
todo-list.component.ts
1
2 import { Component, OnInit } from "@angular/core";
3 import { FormBuilder, FormGroup, Validators } from "@angular/forms";
4 import { Observable } from "rxjs";
5 import { map } from "rxjs/operators";
6
7 import { Todo, TodoService } from "./todo.service";
8
9 @Component({
10 selector: "app-todo",
11 template: `
12 <div *ngFor="let todo of (todos$ | async)">
13 {{ todo.id }} {{ todo.value }}
14 <button (click)="deleteTodo(todo.id)">x</button>
15 </div>
16 `
17 })
18 export class TodoListComponent implements OnInit {
19 todos$: Observable<Todo[]>;
20
21 constructor(private todoService: TodoService) {}
22
23 ngOnInit() {
24 this.todos$ = this.todoService.todos$;
25 }
26
27 deleteTodo(todoId: number) {
28 this.todoService.remove(todoId);
29 }
30 }
31
32
We inject todoService
1
2 constructor(private todoService: TodoService) {}
3
And get hold of a reference to the todo$ observable.
1
2 this.todos$ = this.todoService.todos$;
3
We use the async pipes to subscribe to the todos$ observable. No need to worry about unsubscribing the
observable as angular handles it when using async pipes
1
2 <div *ngFor="let todo of (todos$ | async)">
3 {{ todo.id }} {{ todo.value }}
4 <button (click)="deleteTodo(todo.id)">x</button>
5 </div>
6
deleteTodo deletes the Todo item by calling the remove method of the todoService
1
2 deleteTodo(todoId: number) {
3 this.todoService.remove(todoId);
4 }
5
TodoAdd Component
We use TodoAddComponent to add a new Todo item
todo-add.component.ts
1
2 import { Component, OnInit } from "@angular/core";
3 import { FormBuilder, FormGroup, Validators } from "@angular/forms";
4 import { Observable } from "rxjs";
5 import { map } from "rxjs/operators";
6
7 import { Todo, TodoService } from "./todo.service";
8
9 @Component({
10 selector: "app-todo-add",
11 template: `
12 <div>
13 <form [formGroup]="todoForm" (submit)="onSubmit()">
14 <p>
15 <input type="text" id="value" name="value" formControlName="value" />
16 </p>
17
18 <button type="submit">Add Item</button><br />
19 </form>
20 </div>
21 `
22 })
23 export class TodoAddComponent implements OnInit {
24 todos$: Observable<Todo[]>;
25 todoForm: FormGroup;
26
27 constructor(
28 private todoService: TodoService,
29 private formBuilder: FormBuilder
30 ) {
31 this.todoForm = this.formBuilder.group({
32 id: [""],
33 value: ["", Validators.required]
34 });
35 }
36
37 ngOnInit() {
38 this.todos$ = this.todoService.todos$;
39 }
40
41 onSubmit() {
42 this.todoService.create(this.todoForm.value);
43 this.todoForm.get("value").setValue("");
44 }
45 }
46
47
First inject todoService
1
2 constructor(
3 private todoService: TodoService,
4 private formBuilder: FormBuilder
5 )
6
We get hold of the todos$ observable. We are not doing anything with it But you can subscribe to it to get the latest
list of Todo items.
1
2 ngOnInit() {
3 this.todos$ = this.todoService.todos$;
4 }
5
onSubmit method creates a new Todo item by calling the create method of the todoService.
1
2 onSubmit() {
3 this.todoService.create(this.todoForm.value);
4 this.todoForm.get("value").setValue("");
5 }
6
app.component.html
1
2 <app-todo-add></app-todo-add>
3 <app-todo></app-todo>
4
The ViewChild or ViewChildren decorators are used to Query and get the reference of the DOM element in the
Component. ViewChild returns the first matching element and ViewChildren returns all the matching elements as
a QueryList of items. We can use these references to manipulate element properties in the component.
To Query a DOM element(s), we must supply the query selector, which can be a string or a type as the first argument
to the ViewChild or ViewChildren. The argument static determines whether the query is performed, before or after
the change detection. The read option allows us to query a different token rather than the default and is useful when
the element is associated with multiple types. We will learn all these in this tutorial.
Table of Contents
ViewChild
Syntax
ViewChild Examples
Injecting Component or Directive Reference
Using Template Reference Variable
Injecting HTML Element Using ElementRef
Multiple Instances
ViewChild returns Undefined
Using Static Option in ViewChild
Using the Read Option in ViewChild
Injecting a Provider from the Child Component
Injecting TemplateRef
ViewChildren
Syntax
QueryList
ViewChildren Example
Listening for QueryList Changes
Reference
ViewChild
The ViewChild query returns the first matching element from the DOM and updates the component variable on
which we apply it.
Syntax
The Syntax of the viewChild is as shown below.
1
2 ViewChild(selector: string | Function | Type<any>, opts: { read?: any; static: boolean; }): any
3
We apply the viewChild decorator on a Component Property. It takes two arguments. A selector and opts.
selector: can be a string, a type or a function that returns a string or type. The change detector looks for the first
element that matches the selector and updates the component property with the reference to the element. If the
DOM changes and a new element matches the selector, the change detector updates the component property.
opts: has two options.
static Determines when the query is resolved. True is when the view is initialized (before the first change detection)
for the first time. False if you want it to be resolved after every change detection
read: Use it to read the different token from the queried elements.
ViewChild Examples
Now, let us learn ViewChild using few examples.
Injecting Component or Directive Reference
One of the use cases of ViewChild is to get the reference of the Child Component in the Parent Component and
manipulate its properties. This is one of the ways by which the Parent can communicate with the child components.
For Example consider the following ChildComponent. It has two methods. Increment & Decrement.
1
2 //child.component.ts
3
4 import { Component, ViewChild, AfterViewInit, OnInit, ChangeDetectorRef } from '@angular/core';
5 import { ChildComponent } from './child.component';
6
7 @Component({
8 selector: 'app-root',
9 templateUrl: 'app.component.html' ,
10 styleUrls: ['./app.component.css']
11 })
12 export class AppComponent {
13 title = 'ViewChild Example)';
14
15 showCounter: boolean = true
16
17 @ViewChild(ChildComponent, { static: true }) child: ChildComponent;
18
19 increment() {
20 this.child.increment();
21 }
22
23 decrement() {
24 this.child.decrement();
25 }
26
27 }
28
The above code results in a TypeError: Cannot read property 'increment' of undefined. The error occurs even if we
assign true to showCounter
Because in the above case Angular does not render the child component immediately. But after the first change
detection which detects the value of showCounter and renders the child component.
Since we used static: true, the angular will try to resolve the ViewChild before the first change detection is run.
Hence the child variable always will be undefined.
Now, change the static: false. Now the code will work correctly. I.e because after every change detection the Angular
updates the ViewChild.
Using the Read Option in ViewChild
A Single element can be associated with multiple types.
For Example, consider the following code. #nameInput template variable is now associated with
both input & ngModel
1
2 <input #nameInput [(ngModel)]="name">
3
The viewChild code below, returns the instance of the input element as elementRef.
1
2 @ViewChild('nameInput',{static:false}) nameVar;
3
If we want to get the instance of the ngModel, then we use the Read token and ask for the type.
1
2 @ViewChild('nameInput',{static:false, read: NgModel}) inRef;
3
4 @ViewChild('nameInput',{static:false, read: ElementRef}) elRef;
5 @ViewChild('nameInput', {static:false, read: ViewContainerRef }) vcRef;
6
Every element in Angular is always has a ElementRef and ViewContainerRef associated with it. If the element is a
component or directive then there is always a component or directive instance. You can also apply more than one
directive to an element.
The ViewChild without read token always returns the component instance if it is a component. If not it returns
the elementRef.
Injecting a Provider from the Child Component
You can also inject the services provided in the child component.
1
2 import { ViewChild, Component } from '@angular/core';
3
4 @Component({
5 selector: 'app-child',
6 template: `<h1>Child With Provider</h1>`,
7 providers: [{ provide: 'Token', useValue: 'Value' }]
8 })
9
10 export class ChildComponent{
11 }
12
And in the Parent component, you can access the provider using the read property.
1
2 import { ViewChild, Component } from '@angular/core';
3
4 @Component({
5 selector: 'app-root',
6 template: `<app-child></app-child>`,
7 })
8
9 export class AppComponent{
10 @ViewChild(ChildComponent , { read:'Token', static:false } ) childToken: string;
11 }
12
Injecting TemplateRef
You can access the TemplateRef as shown below
1
2 <ng-template #sayHelloTemplate>
3 <p> Say Hello</p>
4 </ng-template>
5
Component code
1
2 @ViewChild("sayHelloTemplate", { static: false }) tempRef: TemplateRef;
3
ViewChildren
ViewChildren decorator is used to getting the list of element references from the View.
ViewChildren is different from the ViewChild. ViewChild always returns the reference to a single element. If there are
multiple elements the ViewChild returns the first matching element,
ViewChildren always returns all the elements as a QueryList. You can iterate through the list and access each
element.
Syntax
The Syntax of the viewChildren is as shown below. It is very much similar to syntax of viewChild except for
the static option.
1
2 ViewChildren(selector: string | Function | Type<any>, opts: { read?: any; }): any
3
The ViewChildren is always resolved after the change detection is run. i.e why it does not have static option. And also
you cannot refer to it in the ngOnInit hook as it is yet to initialize.
QueryList
The QueryList is the return type of ViewChildren and contentChildren .
QueryList stores the items returned by the viewChildren or contentChildren in a list.
The Angular updates this list, whenever the state of the application change. It does it on each change detection.
The QueryList also Implements an iterable interface. Which means you can iterate over it using for (var i of items) or
use it with ngFor in template *ngFor="let i of items".
Changes can be observed by subscribing to the changes Observable.
You can use the following methods & properties.
first: returns the first item in the list.
last: get the last item in the list.
length: get the length of the items.
changes: Is an observable. It emits a new value, whenever the Angular adds, removes or moves the child elements.
It also supports JavaScript array methods like map(), filter() , find(), reduce(), forEach(), some(). etc
ViewChildren Example
In the example below, we have three input elements all using the ngModel directive
We use the ViewChildren to get the QueryList of all input elements
Finally, we can use the this.modelRefList.forEach to loop through the QueryList and access each element.
1
2 import { ViewChild, Component, ViewChildren, QueryList, AfterViewInit } from '@angular/core';
3 import { NgModel } from '@angular/forms';
4
5 @Component({
6 selector: 'app-viewchildren1',
7 template: `
8 <h1>ViewChildren Example</h1>
9
10 <input name="firstName" [(ngModel)]="firstName">
11 <input name="midlleName" [(ngModel)]="middleName">
12 <input name="lastName" [(ngModel)]="lastName">
13
14 <button (click)="show()">Show</button>
15
16 `,
17 })
18
19 export class ViewChildrenExample1Component {
20
21 firstName;
22 middleName;
23 lastName;
24
25 @ViewChildren(NgModel) modelRefList: QueryList<NgModel>;
26
27 show() {
28
29 this.modelRefList.forEach(element => {
30 console.log(element)
31 //console.log(element.value)
32 });
33 }
34 }
35
Listening for QueryList Changes
We can subscribe to the changes observable to find if any new elements are added/removed or moved.
In the example below, we have included ngIf directive to hide/show the input elements.
We subscribe to the changes observable in the component class. Every time we use the ngIf to hide or add the
component, the changes observable emits the latest QueryList.
1
2 import { ViewChild, Component, ViewChildren, QueryList, AfterViewInit } from '@angular/core';
3 import { NgModel } from '@angular/forms';
4
5 @Component({
6 selector: 'app-viewchildren2',
7 template: `
8 <h1>ViewChildren Example</h1>
9
10 <input *ngIf="showFirstName" name="firstName" [(ngModel)]="firstName">
11 <input *ngIf="showMiddleName" name="midlleName" [(ngModel)]="middleName">
12 <input *ngIf="showlastName" name="lastName" [(ngModel)]="lastName">
13
14
15 <input type="checkbox" id="showFirstName" name="showFirstName" [(ngModel)]="showFirstName">
16 <input type="checkbox" id="showMiddleName" name="showMiddleName" [(ngModel)]="showMiddleName">
17 <input type="checkbox" id="showlastName" name="showlastName" [(ngModel)]="showlastName">
18
19 <button (click)="show()">Show</button>
20
21 `,
22
23 })
24
25 export class ViewChildrenExample2Component implements AfterViewInit {
26
27 firstName;
28 middleName;
29 lastName;
30
31 showFirstName=true;
32 showMiddleName=true;
33 showlastName=true;
34
35 @ViewChildren(NgModel) modelRefList: QueryList<NgModel>;
36
37 ngAfterViewInit() {
38
39 this,this.modelRefList.changes
40 .subscribe(data => {
41 console.log(data)
42 }
43 )
44 }
45
46
47 show() {
48 this.modelRefList.forEach(element => {
49 console.log(element)
50 //console.log(element.value)
51 });
52
53 }
54 }
55
Reference
ViewChild API
ViewChildren API
QueryList API
ElementRef API
ViewContainerRef API
Read More
ngModel
ElementRef
ElementRef in Angular
Leave a Comment / 4 minutes of reading / May 16, 2021
Viewchild, viewchildren & querylist
Renderer2
Angular ElementRef is a wrapper around a native DOM element (HTML element) object. It contains the
property nativeElement, which holds the reference to the underlying DOM object. We can use it to manipulate the
DOM. We use the ViewChild to get the ElementRef of an HTML element in the component class. Angular also
inject ElementRef of the Host element of the component or directive when you request for it in the constructor. In
this tutorial, let us explore how to use ElementRef to get the reference of an HtmlElement & manipulate the DOM in
Angular Applications.
00:10/03:27
Table of Contents
ElementRef
Getting ElementRef in Component Class
Read token
ElementRef Example
ElementRef in Custom Directive
Use with caution
ElementRef & XSS Injection Attack
Reference
ElementRef
The DOM objects are created and maintained by the Browser. They represent the structure and content of the
Document. In a Vanilla JavaScript code, we access these DOM objects to manipulate the View. We can create and
build documents, navigate their structure, and add, modify, or delete elements and content.
Angular provides a lot of tools & techniques to manipulate the DOM. We can add/remove components. It provides a
lot of directives like Class Directive or Style directive. to Manipulate their styles etc.
We may still need to access the DOM element on some occasions. This is where the ElementRef comes into the
picture.
Getting ElementRef in Component Class
To manipulate the DOM using the ElementRef, we need to get the reference to the DOM element in
the component/directive.
To get the reference to DOM elements in the component
Create a template reference variable for the element in the component/directive.
Use the template variable to inject the element into component class using the ViewChild or ViewChildren.
To get the DOM element hosting the component/directive
Ask for ElementRef in the constructor (Angular Dependency injection), the Angular will inject the reference element
hosting the component/directive.
The Renderer2 allows us to manipulate the DOM elements, without accessing the DOM directly. It provides a layer of
abstraction between the DOM element and the component code. Using Renderer2 we can create an element, add a
text node to it, append child element using the appendchild method., etc. We can also add or remove styles, HTML
attributes, CSS Classes & properties, etc. We can also attach and listen to events etc.
Table of Contents
Why not ElementRef?
Using Renderer2
Setting & Removing Styles (setStyle & removeStyle)
Adding / Removing CSS Classes (addClass & removeClass)
Setting or Remove Attributes (setAttribute & removeAttribute)
Setting Property (setProperty)
AppendChild
Insert Text Element (CreateText & appendChild)
Creating new Element (createElement & appendChild)
InsertBefore
Insert Comment
ParentNode & NextSibling
SelectRootElement
Listen to DOM events
Reference
Why not ElementRef?
We can use the nativeElement property of the ElelemtRef to manipulate the DOM. We learned this in our last
tutorial on ElementRef. The nativeElement Property contains the reference to the underlying DOM object. This gives
us direct access to the DOM, bypassing the Angular. There is nothing wrong with using it, but it is not advisable for
the following reasons.
Angular keeps the Component & the view in Sync using Templates, data binding & change detection, etc. All of them
are bypassed when we update the DOM Directly.
DOM Manipulation works only in Browser. You will not able to use the App in other platforms like in a web worker,
in Server (Server-side rendering), or in a Desktop, or in the mobile app, etc where there is no browser.
The DOM APIs do not sanitize the data. Hence it is possible to inject a script, thereby, opening our app an easy target
for the XSS injection attack.
Using Renderer2
First import it from the @angular/core
1
2 import {Component, Renderer2, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
3
inject it into the component
1
2 constructor(private renderer:Renderer2) {
3}
4
Use ElementRef & ViewChild to get the reference to the DOM element, which you want to manipulate.
1
2 @ViewChild('hello', { static: false }) divHello: ElementRef;
3
Use the methods like setProperty , setStyle etc to change the property, styles of the element as shown below.
1
2 this.renderer.setProperty(this.divHello.nativeElement,'innerHTML',"Hello Angular")
3
4 this.renderer.setStyle(this.divHello.nativeElement, 'color', 'red');
5
Code Example
Setting & Removing Styles (setStyle & removeStyle)
Use the setStyle & RemoveStyle to add or remove the styles. It accepts four argument.
The first argument is the element to which we want to apply the style. name of the styles is the second argument.
The value of the style is the third argument. The last argument is Flags for style variations
1
2 abstract setStyle(el: any, style: string, value: any, flags?: RendererStyleFlags2): void
3
4 abstract removeStyle(el: any, style: string, flags?: RendererStyleFlags2): void
5
Example
1
2 //Template
3
4 <div #hello>Hello !</div>
5
6
7 //Component
8 @ViewChild('hello', { static: false }) divHello: ElementRef;
9
10
11 setStyle() {
12 this.renderer.setStyle(this.divHello.nativeElement, 'color', 'blue');
13 }
14
15
16 removeStyle() {
17 this.renderer.removeStyle(this.divHello.nativeElement, 'color');
18 }
19
Use the last option RendererStyleFlags2 to add the !important or to make use of DashCase
Adding / Removing CSS Classes (addClass & removeClass)
Use the methods addClass / removeClass to add or remove classes.
Syntax
1
2 abstract addClass(el: any, name: string): void
3
4
5 abstract removeClass(el: any, name: string): void
6
Example
1
2 //Template
3
4 <div #hello>Hello !</div>
5
6
7
8 //Component
9 @ViewChild('hello', { static: false }) divHello: ElementRef;
10
11 addClass() {
12 this.renderer.addClass(this.divHello.nativeElement, 'blackborder' );
13 }
14
15 removeClass() {
16 this.renderer.removeClass(this.divHello.nativeElement, 'blackborder');
17 }
18
19
Setting or Remove Attributes (setAttribute & removeAttribute)
We can add remove attributes using the setAttribute & removeAttribute
1
2 setAttribute(el: any, name: string, value: string, namespace?: string): void
3
4 removeAttribute(el: any, name: string, namespace?: string): void
5
Example
1
2 //Template
3
4 <h2>Add/ Remove Attributes </h2>
5 <input #inputElement type='text'>
6 <button (click)="addAttribute()">Set Attribute</button>
7 <button (click)="removeAttribute()">Remove Attribute</button>
8
9
10
11 //Component
12
13 @ViewChild('inputElement', { static: false }) inputElement: ElementRef;
14
15
16 addAttribute() {
17 this.renderer.setAttribute(this.inputElement.nativeElement, 'value', 'name' );
18 }
19
20
21 removeAttribute() {
22 this.renderer.removeAttribute(this.inputElement.nativeElement, 'value');
23 }
24
25
Setting Property (setProperty)
Set any property of a DOM element using the setProperty method.
1
2 setProperty(el: any, name: string, value: any): void
3
1
2 setProperty() {
3 this.renderer.setProperty(this.divHello.nativeElement,'innerHTML',"Hello Angular")
4}
5
AppendChild
Use the appendChild to append a new element (child element) to any existing element (parent element).
1
2 appendChild(parent: any, newChild: any): void
3
It accepts two arguments. The first argument is the parent node, where we want to append a new child node. The
second argument is the child node, which you want to add.
The next two examples, shows how to use appendChild.
Insert Text Element (CreateText & appendChild)
CreateText allow us to add text to the DOM.
Example
The following template has a empty div ( #divCreateText)
1
2 //Template
3
4 <h2>Create Text Example</h2>
5 <div #divCreateText> </div>
6 <button (click)="createText()">Create Text</button>
7
Use the ViewChild to inject the reference to the divCreateText in the component.
1
2 @ViewChild('divCreateText', { static: false }) divCreateText: ElementRef;
3
Use the createText method the create text node. At this point it is not added to the DOM.
1
2 const text = this.renderer.createText('Example of Create Text');
3
Use the appendChild method to add it to an existing element (divCreateText).
1
2 this.renderer.appendChild(this.divCreateText.nativeElement, text);
3
Creating new Element (createElement & appendChild)
We can easily create a new element using the createElement & appendChild.
createElement creates a new element, but does not insert it into the DOM. To insert into the DOM, we need to add
it to an element, which already exists in the DOM using appendChild method.
The following example shows how to create a new element and append to the DOM.
First, we inject ElementRef in the constructor. This will inject the DOM element hosting the component/directive.
1
2 constructor(private el: ElementRef,
3 private renderer:Renderer2) {
4 }
5
Create a new div element using the method createElement('div'). It is not yet added to the DOM.
1
2 const div = this.renderer.createElement('div');
3
Make use of the createText('Inserted at bottom') to create a new text node.
1
2 const text = this.renderer.createText('Inserted at bottom');
3
Use appendChild to append the newly created text node to the div element. Note that div is not yet added to the
DOM.
1
2 this.renderer.appendChild(div, text);
3
Finally, we add the div element to an existing DOM element i.e. host element.
1
2 this.renderer.appendChild(this.div.nativeElement, div);
3
The complete code as under. The createElement2 appends the new child node a another div.
1
2 import { Component, Renderer2, OnInit, ElementRef, ViewChild, AfterViewInit, VERSION } from '@angular/core';
3
4 @Component({
5 selector: 'app-create-element',
6 templateUrl: './create-element.component.html',
7 styleUrls: ['./create-element.component.css']
8 })
9 export class CreateElementComponent {
10
11
12 @ViewChild('div', { static: false }) div: ElementRef;
13
14
15 constructor(private el: ElementRef,
16 private renderer:Renderer2) {
17 }
18
19
20 createElement() {
21 const div = this.renderer.createElement('div');
22 const text = this.renderer.createText('Inserted at bottom');
23
24 this.renderer.appendChild(div, text);
25 this.renderer.appendChild(this.el.nativeElement, div);
26 }
27
28
29 createElement2() {
30 const div = this.renderer.createElement('div');
31 const text = this.renderer.createText('Inserted inside div');
32
33 this.renderer.appendChild(div, text);
34 this.renderer.appendChild(this.div.nativeElement, div);
35 }
36
37 }
38
39
1
2 <h2>Renderer2 Create Element</h2>
3
4 <div #div style="border: 1px solid black;">
5 This is a div
6 </div>
7
8 <button (click)="createElement()">Create Element</button>
9 <button (click)="createElement2()">Create Element</button>
10
InsertBefore
We can also insert the new element, before an element in the DOM element using the insertBefore method. The
syntax of insertBefore as shown below.
1
2 insertBefore(parent: any, newChild: any, refChild: any): void
3
parent is the parent node. newChild is the new node, which you want to insert. refChild is the existing child node
before which newChild is inserted.
The following Example inserts a new element before div1.
1
2 <h1>Angular Renderer2 InsertBefore Example</h1>
3
4
5 <div #div1>
6 This is div 1
7 </div>
8
9 <div #div2>
10 This is div 2
11
12 <div #div3>
13 This is div 3
14 </div>
15
16 </div>
17
18
19
20 <button (click)="insertBeforeDiv1()" >Insert Before Div1</button>
21
22 <button (click)="insertBeforeDiv2()" >Insert Before Div2</button>
23
24 <button (click)="insertBeforeDiv3()" >Insert Before Div3</button>
25
First, use the ViewChild to get the reference to the div1. Inject ElementRef, which gives us the reference to the Host
DOM element.
Create a new div element using createElement. Add a text node to it using createText and append it to the div
Use the insertBefore method to add the div element
1
2 import { Component, OnInit, ViewChild, ElementRef, Renderer2 } from '@angular/core';
3
4 @Component({
5 selector: 'app-insert-before',
6 templateUrl: './insert-before.component.html',
7 styleUrls: ['./insert-before.component.css']
8 })
9 export class InsertBeforeComponent {
10
11 @ViewChild('div1', { static: false }) div1: ElementRef;
12 @ViewChild('div2', { static: false }) div2: ElementRef;
13 @ViewChild('div3', { static: false }) div3: ElementRef;
14
15
16 constructor(private renderer:Renderer2, private el:ElementRef) { }
17
18
19
20 insertBeforeDiv1() {
21 const div = this.renderer.createElement('div');
22 const text = this.renderer.createText('This Text is Inserted before the div1');
23 this.renderer.appendChild(div, text);
24
25 this.renderer.insertBefore(this.el.nativeElement,div,this.div1.nativeElement);
26 }
27
28
29
30 insertBeforeDiv2() {
31 const div = this.renderer.createElement('div');
32 const text = this.renderer.createText('This Text is Inserted before the div2');
33 this.renderer.appendChild(div, text);
34
35 this.renderer.insertBefore(this.el.nativeElement,div,this.div2.nativeElement);
36 }
37
38
39
40
41 insertBeforeDiv3() {
42 const div = this.renderer.createElement('div');
43 const text = this.renderer.createText('This Text is Inserted before the div3');
44 this.renderer.appendChild(div, text);
45
46 //Using parentNode to retrieve the Parent Node
47 this.renderer.insertBefore( this.renderer.parentNode(this.div3.nativeElement),div,this.div3.nativeElement);
48 }
49
50
51 }
52
Insert Comment
createComment creates comment node. It accepts comment as the argument. You can then use
the appendChild or insertBefore to insert it anywhere in the DOM.
1
2 createComment(value: string): any
3
ParentNode & NextSibling
ParentNode method returns the parent of a given node in the host element’s DOM.
1
2 //Returns the parent Node of div3
3 this.renderer.parentNode(this.div3.nativeElement);
4
nextSibling method returns the next sibling node of a given node in the host element’s DOM.
1
2 //Returns the next Sibling node of div2
3 this.renderer.nextSibling(this.div2.nativeElement);
4
SelectRootElement
We can also use the selectRoomElement to select a node element based on a selector.
Syntax
1
2 selectRootElement(selectorOrNode: any, preserveContent?: boolean)
3
The first argument is the selector or node. The Renderer2 uses the selector to search for the DOM element and
returns it.
The second argument is preserveContent. If no or undefined, the renderer2 will remove all the child nodes. If yes the
child nodes are not removed.
Example, consider the following template
1
2 <h1>Renderer2 selectRootElement Example</h1>
3
4 <div class="outerDiv" style="border: 1px solid black; padding :5px;">
5
6 <div class="div1" style="border: 1px solid black; margin :5px;">This is Div1</div>
7 <div class="div2" style="border: 1px solid black; margin :5px;">This is Div2</div>
8 <div class="div3" class="div3class" style="border: 1px solid black; margin :5px;">This is Div3</div>
9
10 </div>
11
12
The selectRootElement in the following example returns the element div1 , but it removes all the content it holds.
Because the second argument is false. Change false to true, then the renderer2 will not remove the content.
1
2 exampleDiv1() {
3 const e = this.renderer.selectRootElement('.div1',false);
4 }
5
Examples.
1
2 exampleDiv2() {
3 //Conent is always replaced. becuase preserveContent is false
4 const e = this.renderer.selectRootElement('.div2',false);
5 const t = this.renderer.createText('Content added to div2');
6 this.renderer.appendChild(e, t);
7
8 }
9
10 exampleDiv3() {
11 //Conent is always appended. becuase preserveContent is true
12 const e = this.renderer.selectRootElement('.div3',true);
13 const t = this.renderer.createText('Content added to div3');
14 this.renderer.appendChild(e, t);
15 }
16
Listen to DOM events
You can also, listen to DOM events using the listen method.
The listen method accepts three arguments. the first argument is the DOM element (target). The second argument is
the name of the event (eventName) and the third argument is the callback
1
2 abstract listen(target: any, eventName: string, callback: (event: any) => boolean | void): () => void
3
In the following example, we listen to the click event of a button.
1
2 //Component
3
4 import { Component, OnInit, ViewChild, ElementRef, Renderer2, AfterViewInit } from '@angular/core';
5
6 @Component({
7 selector: 'app-listen-events',
8 templateUrl: './listen-events.component.html',
9 styleUrls: ['./listen-events.component.css']
10 })
11 export class ListenEventsComponent implements AfterViewInit {
12
13 @ViewChild('hello', { static: false }) divHello: ElementRef;
14
15 Count=0
16 clicklistener;
17
18 constructor(private renderer:Renderer2) { }
19
20 ngAfterViewInit() {
21
22 this.clicklistener = this.renderer.listen(this.divHello.nativeElement, 'click', (evt) => {
23 this.Count++;
24 });
25
26 }
27
28 ngOnDestroy() {
29 this.clicklistener.unsubscribe()
30 }
31
32 }
33
Do not forget to unsubscribe to the this.clicklistener.unsubscribe()
1
2 //Template
3
4 <h1>Renderer2 Listen Events Example</h1>
5
6
7 <button #hello>hello</button>
8
9 Click Count {{Count}}
10
Table of Contents
What is Angular Directive
Component Directive
Structural Directives
Commonly used structural directives
ngFor
ngSwitch
ngIf
Attribute Directives
Commonly used Attribute directives
ngModel
ngClass
ngStyle
Building Custom Directives
Summary
What is Angular Directive
The Angular directive helps us to manipulate the DOM. You can change the appearance, behavior, or layout of a
DOM element using the Directives. They help you to extend HTML
There are three kinds of directives in Angular:
Component Directive
Structural directives
Attribute directives
Component Directive
Components are special directives in Angular. They are the directive with a template (view) We covered how to
create Components in Angular tutorial.
Structural Directives
Structural directives can change the DOM layout by adding and removing DOM elements. All structural Directives are
preceded by Asterix symbol
Commonly used structural directives
ngFor
The ngFor is an Angular structural directive, which repeats a portion of the HTML template once per each item from
an iterable list (Collection). The ngFor is similar to ngRepeat in AngularJS
Example of ngFor
1
2 <tr *ngFor="let customer of customers;">
3 <td>{{customer.customerNo}}</td>
4 <td>{{customer.name}}</td>
5 <td>{{customer.address}}</td>
6 <td>{{customer.city}}</td>
7 <td>{{customer.state}}</td>
8 </tr>
9
10
You can read more about the Angular ngFor Directive tutorial.
ngSwitch
The ngSwitch directive lets you add/remove HTML elements depending on a match expression. ngSwitch directive
used along with ngSwitchCase and ngSwitchDefault
The example of ngSwitch
1
2 <div [ngSwitch]="Switch_Expression">
3 <div *ngSwitchCase="MatchExpression1”> First Template</div>
4 <div *ngSwitchCase="MatchExpression2">Second template</div>
5 <div *ngSwitchCase="MatchExpression3">Third Template</div>
6 <div *ngSwitchCase="MatchExpression4">Third Template</div>
7 <div *ngSwitchDefault?>Default Template</div>
8 </div>
9
You can read more about the Angular ngSwitch Directive tutorial.
ngIf
The ngIf Directives is used to add or remove HTML elements based on an expression. The expression must return a
boolean value. If the expression is false then the element is removed, else the element is inserted
Example of ngIf
1
2 <div *ngIf="condition">
3 This is shown if condition is true
4 </div>
5
You can read more about Angular ngIf Directive tutorial.
Attribute Directives
An Attribute or style directive can change the appearance or behavior of an element.
Commonly used Attribute directives
ngModel
The ngModel directive is used the achieve the two-way data binding. We have covered ngModel directive in Data
Binding in Angular Tutorial
ngClass
The ngClass is used to add or remove the CSS classes from an HTML element. Using the ngClass one can create
dynamic styles in HTML pages
Example of ngClass
1
2 <div [ngClass]="'first second'">...</div>
3
ngStyle
ngStyle is used to change the multiple style properties of our HTML elements. We can also bind these properties to
values that can be updated by the user or our components.
Example of ngStyle
1
2 <div [ngStyle]="{'color': 'blue', 'font-size': '24px', 'font-weight': 'bold'}">
3 some text
4 </div>
5
Building Custom Directives
You can also build custom directives in Angular. The Process is to create a JavaScript class and apply
the @Directive attribute to that class. You can write the desired behavior in the class.
Angular ngFor directive iterates over a collection of data like an array, list, etc, and creates an HTML element for
each of the items from an HTML template. It helps us to build lists or tables to display tabular data in a nice way. In
this tutorial, we will look at the syntax and how to use ngFor to display a list of movies using example code.
The ngFor also exports several local variables like Index, First, Last, odd, even & trackby.etc. In this article, we will
learn the following
Open the app.component.ts and add the following code. The code contains a list of Top 10 movies. Let us build a
template to display the movies using ngFor.
1
2 import { Component } from '@angular/core';
3
4 @Component({
5 selector: 'app-root',
6 templateUrl: './app.component.html',
7 })
8 export class AppComponent {
9 title: string ="Top 5 Movies" ;
10
11
12 movies: Movie[] =[
13
14 {title:'Zootopia',director:'Byron Howard, Rich Moore',cast:'Idris Elba, Ginnifer Goodwin, Jason
15 Bateman',releaseDate:'March 4, 2016'},
16 {title:'Batman v Superman: Dawn of Justice',director:'Zack Snyder',cast:'Ben Affleck, Henry Cavill, Amy
17 Adams',releaseDate:'March 25, 2016'},
18 {title:'Captain American: Civil War',director:'Anthony Russo, Joe Russo',cast:'Scarlett Johansson, Elizabeth Olsen,
19 Chris Evans',releaseDate:'May 6, 2016'},
20 {title:'X-Men: Apocalypse',director:'Bryan Singer',cast:'Jennifer Lawrence, Olivia Munn, Oscar
21 Isaac',releaseDate:'May 27, 2016'},
22 {title:'Warcraft',director:'Duncan Jones',cast:'Travis Fimmel, Robert Kazinsky, Ben Foster',releaseDate:'June 10,
23 2016'},
]
24
}
25
26
class Movie {
27
title : string;
28
director : string;
29
cast : string;
30
releaseDate : string;
}
Source code
Using ngFor
To use ngFor,
Create a block of HTML elements, which can display a single movie.
Use the ngFor to repeat the block for each movie in the movies.
Open the app.component.html and add the following code.
1
2 <h1> {{title}} </h1>
3
4 <ul>
5 <li *ngFor="let movie of movies">
6 {{ movie.title }} - {{movie.director}}
7 </li>
8 </ul>
9
10
Source code
We use the ul to display the movies. The li element displays a single movie. We need to repeat the li for each movie.
Hence we apply the ngFor on the li element.
let movie of movies will iterate over the movies collection, which is a property on the component class. movie is
the Template input variable, which represents the currently iterated movie from the collection. We use Angular
Interpolation to display the movie title & name of the director
Here is the output
The Angular generates the following code. You can see li element for every movie.
1
2 <ul _ngcontent-gop-c0="">
3 <li _ngcontent-gop-c0=""> Zootopia - Byron Howard, Rich Moore </li>
4 <li _ngcontent-gop-c0=""> Batman v Superman: Dawn of Justice - Zack Snyder </li>
5 <li _ngcontent-gop-c0=""> Captain American: Civil War - Anthony Russo, Joe Russo </li>
6 <li _ngcontent-gop-c0=""> X-Men: Apocalypse - Bryan Singer </li>
7 <li _ngcontent-gop-c0=""> Warcraft - Duncan Jones </li>
8 </ul>
9
Similarly, you can use the table element to display the movies as shown below. Here we need to repeat
the tr element for each movie. Hence apply the directive on tr
1
2 <div class='panel panel-primary'>
3 <div class='panel-heading'>
4 {{title}}
5 </div>
6
7 <div class='panel-body'>
8 <div class='table-responsive'>
9 <table class='table'>
10 <thead>
11 <tr>
12 <th>Title</th>
13 <th>Director</th>
14 <th>Cast</th>
15 <th>Release Date</th>
16 </tr>
17 </thead>
18 <tbody>
19 <tr *ngFor="let movie of movies;">
20 <td>{{movie.title}}</td>
21 <td>{{movie.director}}</td>
22 <td>{{movie.cast}}</td>
23 <td>{{movie.releaseDate}}</td>
24 </tr>
25 </tbody>
26 </table>
27 </div>
28 </div>
29 </div>
30
Source Code
Here is the output
Nested Array
The following example shows how to use the ngFor in a nested array. The employees array has nested skills array.
1
2 employees = [
3 {
4 name: "Rahul", email: "[email protected]",
5 skills: [{ skill: 'Angular', exp: '2' },{ skill: 'Javascript', exp: '7' },{ skill: 'TypeScript', exp: '3' }
6 ]
7 },
8 {
9 name: "Sachin", email: "[email protected]",
10 skills: [{ skill: 'Angular', exp: '1' },{ skill: 'Android', exp: '3' },{ skill: 'React', exp: '2' }
11 ]
12 },
13 {
14 name: "Laxmna", email: "[email protected]",
15 skills: [{ skill: 'HTML', exp: '2' },{ skill: 'CSS', exp: '2' },{ skill: 'Javascript', exp: '1' }
16 ]
17 }
18 ]
19
Source code
Inside the main loop, use the local variable employee to get the list of skills and loop through it using *ngFor="let
skill of employee.skills;"
1
2 <div class='card'>
3 <div class='card-header'>
4 <p>Nested Array</p>
5 </div>
6
7 <div class='table-responsive'>
8 <table class='table table-bordered table-sm '>
9 <thead class="thead-dark">
10 <tr>
11 <th>Name</th>
12 <th>Mail ID</th>
13 <th>Skills</th>
14 </tr>
15 </thead>
16 <tbody>
17 <tr *ngFor="let employee of employees;">
18 <td>{{employee.name}}</td>
19 <td>{{employee.email}}</td>
20 <td>
21 <table class='table table-sm '>
22 <tbody>
23 <tr *ngFor="let skill of employee.skills;">
24 <td>{{skill.skill}}</td>
25 <td>{{skill.exp}}</td>
26 </tr>
27 </tbody>
28 </table>
29
30 </td>
31 </tr>
32 </tbody>
33 </table>
34 </div>
35 </div>
36
Source code
The ngSwitch is an Angular structural directive, which allows us to add or remove DOM elements. It works in
conjunction with ngSwitchcase, & ngSwitchDefault directives. It is similar to the switch statement of JavaScript. In
this tutorial, we will look at the syntax of ngSwitch, ngSwitchcase & ngSwitchDefault. We will show you how to use
these directives using an example. The examples include ngSwitch Example, multiple ngSwitchCase , Loose Equality
Checks, etc.
Component Class
Create a variable num in your Angular Component class
1
2 num: number= 0;
3
Template
1
2 <div class='card'>
3 <div class='card-header'>
4 ngSwitch Example
5 </div>
6 <div class="card-body">
7 Input string : <input type='text' [(ngModel)]="num" />
8
9 <div [ngSwitch]="num">
10 <div *ngSwitchCase="'1'">One</div>
11 <div *ngSwitchCase="'2'">Two</div>
12 <div *ngSwitchCase="'3'">Three</div>
13 <div *ngSwitchCase="'4'">Four</div>
14 <div *ngSwitchCase="'5'">Five</div>
15 <div *ngSwitchDefault>This is Default</div>
16 </div>
17 </div>
18 </div>
19
Now let us examine the code in detail
1
2 Input string : <input type='text' [(ngModel)] ="num"/>
3
We bind the num variable to the input box.
1
2 <div [ngSwitch]="num">
3
We attach the ngSwitch directive to the div element, then bind it to the expression num.
1
2 <div *ngSwitchCase="'1'">One</div>
3
Next, we have a few ngSwitchCase directives attached to the div element with matching expressions “1”,”2” etc.
Whenever the num matches these expressions, the ngSwitchCase displays the element attached to it else it removes
it from DOM.
1
2 <div *ngSwitchDefault>This is Default</div>
3
The ngSwithcDefault does not take any expression, but it is displays only when all other ngSwitchCase match
expressions fail.
More Examples
The following uses the array of objects instead of a variable.
Component class
1
class item {
2
name: string;
3
val: number;
4
}
5
6
export class AppComponent
7
{
8
items: item[] = [{name: 'One', val: 1}, {name: 'Two', val: 2}, {name: 'Three', val: 3}, {name: 'Four', val: 3}, {name:
9
'Five', val: 3}];
10
selectedValue1: string= 'One';
11
selectedValue2: string= 'One';
12
selectedValue3: string= 'One';
13
selectedValue4: string= 'One';
14
}
15
Template
Note that we have two matches for *ngSwitchCase="'Two'". ngSwitchcase renders both.
1
2 <div class='card'>
3 <div class='card-header'>
4 Multiple ngSwitchCase with same condition
5 </div>
6
7 <div class="card-body">
8 <select [(ngModel)]="selectedValue1">
9 <option *ngFor="let item of items;" [value]="item.name">{{item.name}}</option>
10 </select>
11
12 <div [ngSwitch]="selectedValue1">
13 <p *ngSwitchCase="'One'">One is Selected</p>
14 <p *ngSwitchCase="'Two'">Two is Selected</p>
15 <p *ngSwitchCase="'Two'">Two Again used in another element</p>
16 <p *ngSwitchDefault>This is Default</p>
17 </div>
18 </div>
19
20 </div>
21
You can also make use of ng-template directly instead of *ngSwitchCase. In fact *ngSwitchCase="'One'" is a shortcut
to ng-template [ngSwitchCase]="'One'".
1
2 <div class='card'>
3 <div class='card-header'>
4 ngSwitch using ng-template
5 </div>
6
7 <div class="card-body">
8
9 <select [(ngModel)]="selectedValue2">
10 <option *ngFor="let item of items;" [value]="item.name">{{item.name}}</option>
11 </select>
12
13 <div [ngSwitch]="selectedValue2">
14 <ng-template [ngSwitchCase]="'One'">One is Selected</ng-template>
15 <ng-template [ngSwitchCase]="'Two'">Two is Selected</ng-template>
16 <ng-template ngSwitchDefault>This is Default</ng-template>
17 </div>
18
19 </div>
20 </div>
21
More than one ngSwitchDefault. Works perfectly ok.
1
2 <div class='card'>
3 <div class='card-header'>
4 Multiple ngSwitchDefault Directives
5 </div>
6
7 <div class="card-body">
8 <select [(ngModel)]="selectedValue3">
9 <option *ngFor="let item of items;" [value]="item.name">{{item.name}}</option>
10 </select>
11
12
13 <div [ngSwitch]="selectedValue3">
14 <div *ngSwitchCase="'One'">One is Selected</div>
15 <div *ngSwitchDefault>This is Default 1</div>
16 <div *ngSwitchCase="'Two'">Two is Selected</div>
17 <div *ngSwitchDefault>This is Default 2</div>
18 </div>
19
20
21 </div>
22 </div>
23
Loose Equality Checks
Angular uses loose equality checks to compare the ngSwitchCase expression with the ngSwitch expression. This
means that the empty string "" matches 0.
1
2 <div class='card'>
3 <div class='card-header'>
4 loose equality Empty string, "" matches 0
5 </div>
6
7 <div class="card-body">
8
9 Input string : <input type='text' [(ngModel)]="num" />
10
11 <div [ngSwitch]="num">
12 <div *ngSwitchCase="0">Zero is Selected</div>
13 <div *ngSwitchCase="1">One is Selected</div>
14 <div *ngSwitchCase="2">Two is Selected</div>
15 <div *ngSwitchDefault>This is Default 2</div>
16 </div>
17
18
19 </div>
20 </div>
21
In this guide let us explore how to use ng-content to add external content (content projection) in the Template. We
know how to use @Input decorator to pass data from the parent component to the child component. But it is only
limited to data. We cannot use that technique to pass the content which includes the HTML elements, CSS, etc to the
child component. To do that we have to make use of content projection.
Content projection is a way to pass the HTML content from the parent component to the child component. The child
component will display the template in a designated spot. We use the ng-content element to designate a spot in the
template of the child component. The ng-content also allows us to create multiple slots using the selector attribute.
The parent can send different content to each slot.
Table of Contents
What is ng-content
Without ng-content
ng-content Example
Events
Custom Events
Multiple Projections using ng-content
Example of ng-content select attribute
Select attribute is a CSS selector
ng-content without selector catches all
ngProjectAs
References
Summary
What is ng-content
The ng-content tag acts as a placeholder for inserting external or dynamic content. The Parent component passes
the external content to the child component. When Angular parses the template, it inserts the external content
where ng-content appears in the child component’s template
We can use content projection to create a reusable component. The components that have similar logic & layout and
can be used in many places in the application.
Take an example of a card component. It has a header section, footer section & body section. The contents of these
sections will vary. The ng-content will allow us to pass these sections to the card component from the parent
component. This enables us to use the card component at many places in the app.
Without ng-content
To understand how content projection using ng-content works, first let us build a simple button component
without ng-content.
Create a new Angular application. Add a new component btn.component.ts.It is a simple component, which displays
a button with the caption Click Me
1
2 import { Component } from '@angular/core';
3
4 @Component({
5 selector: 'app-btn',
6 template: `<button>
7 Click Me
8 </button>`
9 })
10 export class BtnComponent {
11 }
12
Now go to the app.component.html.
1
2 <h2>Simple Button Demo</h2>
3 <app-btn></app-btn>
4 <app-btn></app-btn>
5
In the code above, we have two buttons with the caption Click Me show up on the screen as expected.
What if we want to change the caption from the parent. We can do that using the @Input property. But
using @input, we can only set the caption of the button. But we cannot change the look and appearance of the
caption.
ng-content Example
Create a new component FancyBtnComponent. Copy all the codes from BtnComponent except for one change.
Remove Click Me and add <ng-content> </ng-content> instead. This tag acts as a placeholder. You can also think of it
as an argument to the component. The parent component must supply the argument
1
2 import { Component, Output, EventEmitter } from '@angular/core';
3
4 @Component({
5 selector: 'app-fancybtn',
6 template: `
7 <button>
8 <ng-content></ng-content>
9 </button> `
10 })
11 export class FancyBtnComponent {
12 }
13
Now open the app.component.html
1
2 <h2>Button Demo With ng-content</h2>
3 <app-fancybtn>Click Me</app-fancybtn>
4 <app-fancybtn><b>Submit</b></app-fancybtn>
5
The content between <app-fancybtn> </app-fancybtn> is passed to our FancyBtnComponent. The component
displays it in place of ng-content.
The advantage of such a solution is that you can pass any HTML content.
Events
The events like click, input, etc bubble up. Hence can be captured in the parent as shown below
1
2 **app.component.html**
3
4 <h2>Button with click event</h2>
5 <app-fancybtn (click)="btnClicked($event)"><b>Submit</b></app-fancybtn>
6
7
8 ** App.component.ts ***
9
10 btnClicked($event) {
11 console.log($event)
12 alert('button clicked')
13 }
14
But if you have more than one button, then you may have to inspect the $event argument to check, which button
responsible for the event.
Custom Events
You can create custom events using the @output as shown in below
1
2 @Output() someEvent:EventEmitter =new EventEmitter();
3
4 raiseSomeEvent() {
5 this.someEvent.emit(args);
6}
7
In parent component
1
2 <app-fancybtn (someEvent)=”DoSomething($event)”><b>Submit</b></app-fancybtn>
3
Multiple Projections using ng-content
The button example is a very simple example. The ng-content is much more powerful than that. It allows us to create
multiple slots in the template. Each slot must define a selector. You can think this as a multiple arguments to the
component
In the parent component we can create different contents and each of those contents can be projected into any of
those slots depending on their selector. To implement this we make use of the ng-content Select attribute. The
select attribute is a CSS Selector
Example of ng-content select attribute
For Example, create a new component card.component.ts
1
2 import { Component } from '@angular/core';
3
4
5 @Component({
6 selector: 'app-card',
7 template: `
8 <div class="card">
9 <div class="header">
10 <ng-content select="header" ></ng-content>
11 </div>
12 <div class="content">
13 <ng-content select="content" ></ng-content>
14 </div>
15 <div class="footer">
16 <ng-content select="footer" ></ng-content>
17 </div>
18 </div>
19 `,
20 styles: [
21 ` .card { min- width: 280px; margin: 5px; float:left }
22 .header { color: blue}
23 `
24 ]
25 })
26 export class CardComponent {
27 }
28
29
In the above example, we have three ng-content slots, each have a selector header,content & footer
Now open the app.component.html add the following code
1
2 <app-card>
3 <header><h1>Angular</h1></header>
4 <content>One framework. Mobile & desktop.</content>
5 <footer><b>Super-powered by Google </b></footer>
6 </app-card>
7
8 <app-card>
9 <header><h1 style="color:red;">React</h1></header>
10 <content>A JavaScript library for building user interfaces</content>
11 <footer><b>Facebook Open Source </b></footer>
12 </app-card>
13
Select attribute is a CSS selector
You can use any CSS selector as the select attribute. Like class, element, id attributes, etc. For Example, the above
card component using the CSS class
1
2 import { Component } from '@angular/core';
3
4 @Component({
5 selector: 'card',
6 template: `
7 <div class="card">
8 <div class="header">
9 <ng-content select=".header" ></ng-content>
10 </div>
11 <div class="content">
12 <ng-content select=".content" ></ng-content>
13 </div>
14 <div class="footer">
15 <ng-content select=".footer" ></ng-content>
16 </div>
17 </div>
18 `,
19 styles: [
20 ` .card { width: 280px; margin: 5px; float:left; border-width:1px; border-style:solid ; }
21 .header { color: blue}
22 `
23 ]
24 })
25 export class CardComponent {
26
And in the component, we use it as
1
2 <card>
3 <div class="header">
4 <h1>Angular</h1>
5 </div>
6 <div class="content">One framework. Mobile & desktop.</div>
7 <div class="footer"><b>Super-powered by Google </b></div>
8 </card>
9
10 <card>
11 <div class="header">
12 <h1 style="color:red;">React</h1>
13 </div>
14 <div class="content">A JavaScript library for building user interfaces</div>
15 <div class="footer"><b>Facebook Open Source </b></div>
16 </card>
17
Similarly, you can use the various CSS Selectors as shown below
1
2 <ng-content select="custom-element" ></ng-content>
3 <ng-content select=".custom-class" ></ng-content>
4 <ng-content select="[custom-attribute]" ></ng-content>
5
ng-content without selector catches all
Now, in the following example, the last paragraph does not belong to any ng-content slots. Hence ng-content will
not project the last para as it cannot determine where to add.
1
2 <card>
3 <div class="header"><h1>Typescript</h1></div>
4 <div class="content">Typescript is a javascript for any scale</div>
5 <div class="footer"><b>Microsoft </b></div>
6 <p>This text will not be shown</p>
7 </card>
8
To solve the above issue, we can include ng-content without any selector. It will display all the content, which cannot
be projected into any other slots.
1
2 import { Component } from '@angular/core';
3
4
5 @Component({
6 selector: 'app-card',
7 template: `
8 <div class="card">
9 <div class="header">
10 <ng-content select="header" ></ng-content>
11 </div>
12 <div class="content">
13 <ng-content select="content" ></ng-content>
14 </div>
15 <div class="footer">
16 <ng-content select="footer" ></ng-content>
17 </div>
18 <ng-content></ng-content>
19 </div>
20 `,
21 styles: [
22 ` .card { min- width: 280px; margin: 5px; float:left }
23 .header { color: blue}
24 `
25 ]
26 })
27 export class CardComponent {
28 }
29
ngProjectAs
Sometimes it becomes necessary to wrap the component using the ng-container. Most of the time when you use a
structural directive like ngIf or ngSwitch.
In the following example, we enclosed the header inside the ng-container.
1
2 <card>
3 <ng-container>
4 <div class="header">
5 <h1 style="color:red;">React</h1>
6 </div>
7 </ng-container>
8 <div class="content">A JavaScript library for building user interfaces</div>
9 <div class="footer"><b>Facebook Open Source </b></div>
10 </card>
11
12
Because of the ng-container, the header section is not projected to the header slot. Instead, it is projected to the ng-
content slot which does not have a selector set.
To help in such a scenario, you can make use of ngProjectAs attribute as shown below.
1
2 <card>
3 <ng-container ngProjectAs="header">
4 <div>
5 <h1 style="color:red;">React</h1>
6 </div>
7 </ng-container>
8 <div class="content">A JavaScript library for building user interfaces</div>
9 <div class="footer"><b>Facebook Open Source </b></div>
10 </card>
11
References
Source Code
Responding to projected content changes
ng-content the hidden docs
ng-container
@Input, @Output & EventEmitter
ngIf
ngSwitch
ngFor
Child/Nested Components in Angular
Angular @input, @output & EventEmitter
14 Comments / 7 minutes of reading / May 16, 2021
ng-content & Content Projection
Template Reference Variable
In this guide let us learn how to make use of @input, @output & EventEmitter in Angular. We use these decorators
to pass data from parent to child component & vice versa. @Input defines the input property in the component,
which the parent component can set. The @output defines the output property (event), which we raise in the child
component using the EventEmitter. The parent listens to these events.
Table of Contents
@input, @output & Eventemitter
@input
@output
EventEmitter
@input, @output & Eventemitter Example
Child Component
Parent Component
Notes on @Input & @Output
You can also pass the optional name
Intercept input property changes with a setter
Subscribe to @Input changes using ngChanges
EventEmitters are observable
Pass by reference
References
Summary
@input, @output & Eventemitter
@input
Input decorator marks the property as the input property. I.e it can receive data from the parent component. The
parent component uses the property binding to bind it to a component property. Whenever the value in the parent
component changes angular updates the value in the child component.
Example
Consider the following component class
1
2 @Component({
3 selector: 'app-customer-detail',
4 templateUrl: './customer-detail.component.html',
5 styleUrls: ['./customer-detail.component.css']
6 })
7 export class CustomerDetailComponent implements OnInit {
8 @Input() customer:Customer;
9 }
10
We have Input decorator on the customer property. The component expects that the parent component will supply
its value.
The parent component supplies the customer object using the property binding syntax. We add a square bracket
around the customer property. Assign template expression (selectedCustomer) to it, which is a property in the
parent component.
1
2 <app-customer-detail [customer]="selectedCustomer"></app-customer-detail>
3
@output
Output decorates the property as the output property. We initialize it as an EventEmitter. The child component
raises the event and passes the data as the argument to the event. The parent component listens to events
using event binding and reads the data.
Example
1
2 //Declare the property
3 @Output() customerChange:EventEmitter<Customer> =new EventEmitter<Customer>();
4
5 //Raise the event to send the data back to parent
6 update() {
7 this.customerChange.emit(this.customer);
8}
9
The customerChange is the Output property and is of type EventEmitter.
In the parent component, we subscribe to the event using the event binding syntax. Use the () around the event
name (customerChange) and assign a template statement (update($event)) to it. It receives the data in
the $event argument.
1
<app-customer-detail [customer]="selectedCustomer" (customerChange)="update($event)"></app-customer-
2
detail>
3
Remember you must use the argument name as $event.
EventEmitter
EventEmitter is responsible for raising the event. The @output property normally is of type EventEmitter. The child
component will use the emit() method to emit an event along with the data.
1
2 //Define output property
3 @Output() customerChange:EventEmitter<Customer> =new EventEmitter<Customer>();
4
5 //Raise the event using the emit method.
6 update() {
7 this.customerChange.emit(this.customer);
8}
9
Now let us build an app to learn how to use Input, output & EventEmitter
This guide explains the Template Reference Variable in Angular. We find out what template reference variable is.
How to define and use it in Angular.
Table of Contents
Template Reference Variable
Defining Template Reference variable
Template Reference variable Example
HTML Element
Pass Variable to Component class
Component/Directive
ExportAs
The safe navigation operator ( ? )
Template Driven Forms
Template Input Variable
Variable Scope
Child scope
References
Summary
Template Reference Variable
The Template reference variable is a reference to any DOM element, component or a directive in the Template. We
can use it elsewhere in the template. We can also pass it to a method in the component. It can contain a reference
to elements like h1, div, etc
Defining Template Reference variable
We declare Template reference variables using # followed by the name of the variable ( #variable). We can also
declare them using #variable="customer" when the component/directive defines a customer as
the exportAs Property.
For Example
HTML Element
1
2 <input type="text" #firstName>
3
Component/Directive
1
2 <app-customer #customerList=”customer”></app-customer>
3
Component/Directive with exportAs
1
2 <app-customer #customerList=”customer”></app-customer>
3
Template Reference variable Example
Now let us create a simple sample application to learn how to use a template reference variable
Create a new application
1
2 ng new templateVariable
3
HTML Element
The following Example code defines the #firstName & #lastName template reference variables. They both contain
the reference to the input HTML Element.
The input elements contain the value property. Hence we can use it to display the welcome message as shown
below.
app.component.html
1
2 <h1>{{title}}</h1>
3
4 <p>
5 <label for="firstName">First Name</label>
6 <input (keyup)="0" type="text" #firstName id="firstName">
7 </p>
8
9 <p>
10 <label for="lastName">Last Name</label>
11 <input (keyup)="0" type="text" #lastName id="lastName">
12 </p>
13
14 <b>Welcome {{firstName.value}} {{lastName.value}} </b>
15
We have used (keyup)="0" on the input element. It does nothing but it forces the angular to run the change
detection. change detection, in turn, updates the view.
The Angular updates the view, when it runs the change detection. The change detection runs only in response to
asynchronous events, such as the arrival of HTTP responses, raising of events, etc. In the example above whenever
you type on the input box, it raises the keyup event. It forces the angular to run the change detection, hence the
view gets the latest values.
Pass Variable to Component class
You can also pass the variables to the component as shown below. Add this code app.component.html
1
2 <p>
3 <button (click)="sayHello(firstName, lastName)"> Say Hello</button>
4 </p>
5
6
Add this to app.component.ts
1
2 sayHello(firstName, lastName) {
3 alert('Hello '+firstName.value+' '+ lastName.value)
4}
5
The Angular Observable tutorial covers what is observable in Angular and how to use Observables
in Angular applications. When we talk about Angular Observable, we hear a lot of terms like Reactive programming,
data streams, Observable, Observers, RxJS, etc. It is very important to understand these terms before we start using
the observables
Rx stands from Reactive programming. It is defined as programming with asynchronous data streams. So it is
important that you understand what is data stream is.
Table of Contents
What is a data stream
Reactive Programming
What is RxJS
What is an Observable in Angular
Who are observers (subscribers)
Angular Observable tutorial
Import the required libraries
Observable Creation
Subscribing to the observable
Adding interval
Error event
Complete Event
Observable Operators
Unsubscribing from an Observable
References
Summary
What is a data stream
A stream is a data, which arrives over a period of time. The stream of data can be anything. Like variables, user
inputs, properties, caches, data structures, and even failures, etc
Consider the example of a sequence of x & y positions of mouse click events. Assume that user has clicked on the
locations (12,15), (10,12), (15,20) & (17,15) in that order.
The following diagram shows how the values arrive over a period of time. As you can see stream emits the values as
they happen i.e asynchronously.
mouse
click events as data streams
Filtering debounceTime,
distinctUntilChanged, filter,
take, takeUntil, takeWhile, takeLast, first, last, single, skip, skipUntil, skipWhile, skipLast,
Multicasting share
Unsubscribing from an Observable
We need to unsubscribe to close the observable when we no longer require it. If not it may lead to memory leak &
Performance degradation.
To Unsubscribe from an observable, we need to call the Unsubscribe() method on the subscription. It will clean up all
listeners and frees up the memory.
To do that, first, create a variable to store the subscription
1
2 obs: Subscription;
3
Assign the subscription to the obs variable
1
2
3 this.obs = this.src.subscribe(value => {
4 console.log("Received " + this.id);
5 });
6
7
Call the unsubscribe() method in the ngOnDestroy method.
1
2 ngOnDestroy() {
3 this.obs.unsubscribe();
4}
5
When we destroy the component, the observable is unsubscribed and cleaned up.
But, you do not have to unsubscribe from every subscription. For Example, the observables, which emits the
complete signal, close the observable.
To learn more about it refer to the tutorial Unsubscribing from an Observable in Angular.
References
observables
RX-library
observables in angular
Practical observable usage
Comparing observables
Observable Design Pattern
Summary
Reactive programming is about programming the stream. The RxJS library brings Reactive Programming into Angular.
Using RxJs, we can create an observable, which can emit the next value, error, and complete signals to the subscriber
of the observable.
In the next few tutorials, we will learn more about the RxJs Observable
Read More
Angular Tutorial
Angular Observable Tutorial
Create Observable from a string, array. object, collection
Observable from events using fromEvent
Observable pipe
Map Operator
Filter Operator
Tap Operator
SwitchMap
MergeMap
ConcatMap
ExhaustMap
take, takeUntil, takeWhile, takeLast
First, last & Single
Skip, SkipWhile, SkipUntil & SkipLast
Scan & Reduce
DebounceTime & Debounce
Delay & DelayWhen
ThrowError
CatchError
ReTry & ReTryWhen
Unsubscribe from an observable
Subjects in Angular
ReplaySubject, BehaviorSubject & AsyncSubject
Angular Subject Example
Create observable from a string, array & object in angular
4 Comments / 5 minutes of reading / June 14, 2020
Angular Observable Tutorial
Observable from Event
In this tutorial, we will show you how to create observable using create, of, from operators in Angular. We can use
them to create new observable from the array, string, object, collection or any static data. Also learn the difference
between the Of & From operators. If you are new to observable, we recommend you to read the Angular
observable before continuing here.
Table of Contents
Observable creation functions
Create
Observable Constructor
Of Operator
observable from an array
observable from a sequence of numbers
observable from string
observable from a value, array & string
From Operator
observable from an array
Observable from string
Observable from collection
Observable from iterable
Observable from promise
Of Vs From
References
Summary
Observable creation functions
There are many ways to create observable in Angular. You can make use of Observable Constructor as shown in
the observable tutorial. There are a number of functions that are available which you can use to create new
observables. These operators help us to create observable from an array, string, promise, any iterable, etc. Here are
some of the operators
create
defer
empty
from
fromEvent
interval
of
range
throw
timer
All the creation related operators are part of the RxJs core library. You can import it from the ‘rxjs’ library
Create
The Create method is one of the easiest. The create method calls the observable constructor behind the scene.
Create is a method of the observable object, Hence you do not have to import it.
1
2 ngOnInit() {
3
4 //Observable from Create Method
5 const obsUsingCreate = Observable.create( observer => {
6 observer.next( '1' )
7 observer.next( '2' )
8 observer.next( '3' )
9
10 observer.complete()
11 })
12
13 obsUsingCreate
14 .subscribe(val => console.log(val),
15 error=> console.log("error"),
16 () => console.log("complete"))
17 }
18
19
20
21 ****Output *****
22 1
23 2
24 3
25 Complete
26
To use from you need to import it from rxjs library as shown below.
1
2 import { from } from 'rxjs';
3
observable from an array
The following example converts an array into an observable. Note that each element of the array is iterated and
emitted separately.
1
2 ngOnInit() {
3
4 const array3 = [1, 2, 3, 4, 5, 6, 7]
5 const obsfrom1 = from(array3);
6 obsfrom1.subscribe(val => console.log(val),
7 error => console.log("error"),
8 () => console.log("complete"))
9
10 }
11
12 *** Output ****
13 1
14 2
15 3
16 4
17 5
18 6
19 7
20 complete
21
Observable from string
The from operator iterates over each character of the string and then emits it. The example is as shown below.
1
2 ngOnInit() {
3 const obsfrom2 = from('Hello World');
4 obsfrom2.subscribe(val => console.log(val),
5 error => console.log("error"),
6 () => console.log("complete"))
7 }
8
9
10 *** Output ****
11 H
12 e
13 l
14 l
15 o
16
17 W
18 o
19 r
20 l
21 d
22 complete
23
Observable from collection
Anything that can be iterated can be converted to observable. Here is an example using a collection.
1
2 ngOnInit() {
3 let myMap = new Map()
4 myMap.set(0, 'Hello')
5 myMap.set(1, 'World')
6 const obsFrom3 = from(myMap);
7 obsFrom3.subscribe(val => console.log(val),
8 error => console.log("error"),
9 () => console.log("complete"))
10 )
11
12 *** output ***
13 [0, "Hello"]
14 [1, "World"]
15 complete
16
Observable from iterable
Any Iterable types like Generator functions can be converted into an observable using from the operator.
1
2 ngOnInit() {
3 const obsFrom4 = from(this.generateNos())
4 obsFrom4.subscribe(val => console.log(val),
5 error => console.log("error"),
6 () => console.log("complete"))
7 }
8
9 *generateNos() {
10 var i = 0;
11 while (i < 5) {
12 i = i + 1;
13 yield i;
14 }
15
16
17 *** Output ***
18 1
19 2
20 3
21 4
22 5
23
Observable from promise
Use it to convert a Promise to an observable
1
2 ngOnInit() {
3 const promiseSource = from(new Promise(resolve => resolve('Hello World!')));
4 const obsFrom5 = from(promiseSource);
5 obsFrom5.subscribe(val => console.log(val),
6 error => console.log("error"),
7 () => console.log("complete"))
8 }
9
10 *** Output ****
11 Hello World
12 complete
13
Of Vs From
Of from
emits each argument as it is without changing anything iterates over the argument and emits each value
Angular provides FromEvent method to create an observable from DOM events directly. In this article let us learn
how to do that by creating an observable from the button click event, keyup even & scroll events.
Table of Contents
Syntax
Example of fromEvent
How it works
fromevent from button click
fromevent from scroll
fromevent from keyup
Reference
Syntax
1
2 fromEvent<T>(target: FromEventTarget<T>,
3 eventName: string,
4 options: EventListenerOptions,
5 resultSelector: (...args: any[]) => T): Observable<T>
6
FromEventTarget is the first argument to fromevent. It can be a DOM EventTarget, Node.js EventEmitter, JQuery-like
event target, NodeList or HTMLCollection. The target must have a method to register/unregister the event handler.
(addEventListener/ removeEventListener in case of DOM Event target)
eventName is the second argument, which is a type of event we want to listen to.
Options are the additional argument that we want to pass to , when registering the event handler
i.e addEventListener
resultSelector is optional and will be deprecated in future versions.
Example of fromEvent
To create an observable from any event, first, we need to get the reference to DOM element using
the viewchild & ElementRef. For example the following code gets the reference to the button element with the
id #btn
1
2 //Template
3 <button #btn>Button</button>
4
1
2 //Component
3
4 @ViewChild('btn', { static: true }) button: ElementRef;
5
The code this.button.nativeElement returns the native DOM element. We pass this as the first argument to
the fromEvent to create an observable to the click event.
1
2 buttonClick() {
3 this.buttonSubscription = fromEvent(this.button.nativeElement, 'click')
4 .subscribe(res => console.log(res));
5 }
6
We can invoke the above method from the ngAfterViewInit method. Note that the @ViewChildwill not initialize
the btn element until the ngOnInit Hence we are using the ngAfterViewInit here.
1
2 ngAfterViewInit() {
3 this.buttonClick();
4 }
5
6
How it works
When we subscribe to an observable, which we created using the fromEvent method, it registers the event handler
using the addEventListener in the DOM element. Whenever the user clicks on the button, fromevent captures the
value and emits it to the subscriber as the first argument. When we unsubscribe, it unregisters the event handler
using the removeEventListener.
fromevent from button click
The following is the complete code of fromevent from a button click.
1
2 import { Component, Input, ViewChild, ElementRef, AfterViewInit, OnInit, OnDestroy } from '@angular/core';
3 import { Observable, of, from, fromEvent } from 'rxjs';
4 import { debounceTime } from 'rxjs/operators';
5
6 @Component({
7 selector: 'app-root',
8 templateUrl: './app.component.html',
9 styleUrls: ['./app.component.css']
10 })
11 export class AppComponent implements AfterViewInit , OnInit, OnDestroy {
12
13 title = 'Angular fromEvent Example';
14
15 @ViewChild('btn', { static: true }) button: ElementRef;
16
17 buttonSubscription
18
19 constructor(private elm: ElementRef) {
20 }
21
22 ngOnInit() {
23 }
24
25
26 ngAfterViewInit() {
27 this.buttonClick();
28 }
29
30
31 buttonClick() {
32 this.buttonSubscription = fromEvent(this.button.nativeElement, 'click')
33 .pipe(debounceTime(300))
34 .subscribe(res => console.log(res));
35 }
36
37
38 ngOnDestroy() {
39 this.buttonSubscription.unsubscribe()
40 }
41
42 }
43
fromevent from scroll
The following code shows how to create observable from the window scroll event
1
2 scroll() {
3 const source = fromEvent(window, 'scroll');
4 source.subscribe(val => console.log(val));
5 }
6
fromevent from keyup
The following code shows how to create observable from a keyUp event.
1
2 //Component
3
4 @ViewChild('name', { static: true }) name: ElementRef;
5
6 ngAfterViewInit() {
7 fromEvent(this.name.nativeElement, 'keyup')
8 .subscribe(res => console.log(res));
9 }
10
Using Angular observable pipe with example
3 Comments / 4 minutes of reading / July 2, 2020
Observable from event
Angular Map
The pipe method of the Angular Observable is used to chain multiple operators together. We can use the pipe as a
standalone method, which helps us to reuse it at multiple places or as an instance method. In this tutorial, we will
take a look at the pipe and learn how to use it in an Angular Application. We will show you examples
of pipe using map, filter & tap operators.
Table of Contents
RxJs Operators
Using pipe to combine operators
Pipe as an instance method
Example : Pipe with Map, Filter & Tap
Pipe as stand alone method
Example
References
RxJs Operators
The operators are very important components of the Rxjs library. They are functions that take an observable as input
and transform it into a new observable and return it. We use them to manipulate the observable data stream.
For Example.
Map operator applies a given project function to each value emitted by the source Observable and emits the
resulting values as an Observable.
Filter operator filter items from the source observable based on some condition and returns the filtered value as a
new observable
Filtering debounceTime,
AREA OPERATORS
distinctUntilChanged, filter,
take, takeUntil, takeWhile, takeLast, first, last, single, skip, skipUntil, skipWhile, skipLast,
Multicasting Share
The Angular observable Map operator takes an observable source as input. It applies a project function to each of
the values emitted by the source observable and transforms it into a new value. It then emits the new value to the
subscribers. We use a Map with a Pipe, which allows us to chain multiple operators together. In this guide, we’re
going to learn how to use the Map operator with examples like converting the source to upper case, Using Map the
Angular HTTP Request, with DOM events, filtering the input data, and using multiple Maps together, etc.
Table of Contents
Syntax
Using Observable Map
Map Examples
Convert input to upper case
Map to a Single Property
Using Map with HTTP Request
Using with event
map with filter
Multiple map
References
Syntax
The syntax of the map operator is as follows.
1
2 map<T, R>(project: (value: T, index: number) => R, thisArg?: any): OperatorFunction<T, R>
3
project: is a function that we use to manipulate the values emitted by the source observable. The project can accept
two arguments. one is value i.e. the value emitted by the observable. The second argument is index number.
The index number starts from 0 for the first value emitted and incremented by one for every subsequent value
emitted. It is similar to the index of an array.
thisArg: is optional and default is undefined.It defines what this is in the project function.
Using Observable Map
To use map first we need to import it from the rxjs/operators library.
1
2 import { map } from 'rxjs/operators'
3
Next, create an observable from array of numbers as shown below.
1
2 srcArray = from([1, 2, 3, 4]);
3
Use the pipe method to and invoke the map method.
1
2 multiplyBy2() {
3 this.srcArray
4 .pipe(map(val => { return val * 2}))
5 .subscribe(val => { console.log(val)})
6 }
7
The project function accepts only one argument val and returns it multiplied by 2.
1
2 map(val => { return val * 2})
3
Finally, we subscribe and print the result in console. The output is 2,4,6,8
The following image explains how values from the source observable ( i.e.1,2,3,4 ) go through the map which
transforms it into new values by multiplying it by 2.
The Filter Operator in Angular filters the items emitted by the source Observable by using a condition (predicate). It
emits only those values, which satisfies the condition and ignores the rest.
Table of Contents
Filter in Angular
Filter Example
Filter Empty or undefined
Filter object or array
Reference
Filter in Angular
Filter is the simplest and most used RxJs Operator in Angular. The Filter Operator takes 2 arguments.
Syntax
1
2 filter<T>(predicate: (value: T, index: number) => boolean, thisArg?: any): MonoTypeOperatorFunction<T>
3
The first argument is the predicate function. This function is evaluated against each value of the source observable.
Filter emits only those values which satisfies the the predicate. The predicate function takes 2 parameters. The first
one is the value emitted by the source. The second argument is zero based index.
The second argument thisArg is Optional. It determines the value of this in the predicate function
Filter Example
The following example filter function returns true only if the value is an even number.
1
2 import { Component } from "@angular/core";
3 import { filter } from "rxjs/operators";
4 import { interval, of, timer } from "rxjs";
5
6 @Component({
7 selector: "my-app",
8 template: `
9 <h1>Filter Example</h1>
10 `,
11 styleUrls: ["./app.component.css"]
12 })
13 export class AppComponent {
14 ngOnInit() {
15 of(1,2,3,4,5,6,7,8,9,10)
16 .pipe(
17 filter(val => {
18 return val %2==0;
19 }),
20 )
21 .subscribe(val => console.log(val));
22 }
23 }
24
25
26 ***Console***
27 2
28 4
29 6
30 8
31 10
32
33
Source Code
Filter Empty or undefined
1
2 filter(value => value !== undefined && value !== null)
3
Filter object or array
1
2 import { Component } from "@angular/core";
3 import { filter } from "rxjs/operators";
4 import { interval, of, timer } from "rxjs";
5 import { fromArray } from "rxjs/internal/observable/fromArray";
6
7 @Component({
8 selector: "my-app",
9 template: `
10 <h1>Filter Example</h1>
11 `,
12 styleUrls: ["./app.component.css"]
13 })
14 export class AppComponent {
15 values = [
16 {
17 name: "John",
18 age: 30
19 },
20 {
21 name: "alex",
22 age: 40
23 }
24 ];
25
26 ngOnInit() {
27 fromArray(this.values)
28 .pipe(
29 filter(val => {
30 return val.age > 30;
31 })
32 )
33 .subscribe(val => console.log(val));
34 }
35 }
36
37
Tap operator in Angular observable
Leave a Comment / 3 minutes of reading / January 26, 2021
Filter
SwitchMap
The Angular Tap RxJs operator returns an observable that is identical to the source. It does not modify the stream in
any way. Tap operator is useful for logging the value, debugging the stream for the correct values, or perform any
other side effects.
Syntax
1
2 tap(nextOrObserver: function, error: function, complete: function): Observable
3
Table of Contents
Tap Operator Example
Debugging the Observable
Error & Complete callbacks
Reference
Tap Operator Example
In the following example, we create an observable using the of operator. We use the pipe to chain the tap operator,
which just logs the values of the source observable into the console.
1
2 import { Component, VERSION } from "@angular/core";
3 import { tap } from "rxjs/operators";
4 import { of } from "rxjs";
5
6 @Component({
7 selector: "my-app",
8 template: `
9 <h1>Tap Example</h1>
10 `,
11 styleUrls: ["./app.component.css"]
12 })
13 export class AppComponent {
14 ngOnInit() {
15 of(1, 2, 3, 4, 5)
16 .pipe(
17 tap(val => {
18 console.log("Tap " + val);
19 })
20 )
21 .subscribe(val => console.log("at Subscriber " + val));
22 }
23
24 }
25
26
27
28
29 ***Console
30
31 Tap 1
32 at Subscriber 1
33 Tap 2
34 at Subscriber 2
35 Tap 3
36 at Subscriber 3
37 Tap 4
38 at Subscriber 4
39 Tap 5
40 at Subscriber 5
41
42
Source Code
if we simply pass the console.log function to the tap operator and the results will be same.
1
2 of(1, 2, 3, 4, 5)
3 .pipe(tap(console.log))
4 .subscribe(val => console.log("at Subscriber " + val));
5
Tap does not modify the source observable in any way
For Example changing the source any way in the tap operator as in the example below, will have no effect.
1
2 of(1, 2, 3, 4, 5)
3 .pipe(
4 tap(val => {
5 val=val+1
6 console.log("Tap " + val);
7 return val;
8 })
9 )
10 .subscribe(val => console.log("at Subscriber " + val));
11
Debugging the Observable
One of the use cases for the tap operator is using it to debug the Observable for the correct values.
The map operator in the following example, adds 5 to the source observable. To debug it, we can add the two tap
operators. One before and one after it and inspect the values.
1
2 of(1, 2, 3, 4, 5)
3 .pipe(
4 tap(val => {
5 console.log("before " +val);
6 }),
7 map(val => {
8 return val + 5;
9 }),
10 tap(val => {
11 console.log("after " +val);
12 })
13 )
14 .subscribe(val => console.log(val));
15
16
17
18 **Console**
19 before 1
20 after 6
21 6
22 before 2
23 after 7
24 7
25 before 3
26 after 8
27 8
28
Source Code
Error & Complete callbacks
We can also use the tap operator to log the error and complete callbacks as shown in the example below.
1
2 import { Component, VERSION } from "@angular/core";
3 import { FormControl, FormGroup } from "@angular/forms";
4 import { debounce, map, tap } from "rxjs/operators";
5 import { interval, of, Subscription } from "rxjs";
6
7 @Component({
8 selector: "my-app",
9 template: `
10 <h1>Tap Example</h1>
11
12
13 `,
14 styleUrls: ["./app.component.css"]
15 })
16 export class AppComponent {
17 ngOnInit() {
18 of(1, 2, 3, 4, 5)
19 .pipe(
20 tap(val => {
21
console.log("Before " + val);
22
}),
23
map(val => {
24
if (val == 3) {
25
throw Error;
26
}
27
return val + 5;
28
}),
29
tap(
30
val => {
31
console.log("After " + val);
32
},
33
err => {
34
console.log("Tap Error");
35
console.log(err);
36
},
37
() => {
38
console.log("Tap Complete");
39
}
40
)
41
)
42
.subscribe(val => console.log(val));
43
}
44
45
ngOnDestroy() {}
46
}
47
48
49
***Console ***
50
Before 1
51
After 6
52
6
53
Before 2
54
After 7
55
7
56
Before 3
57
Tap Error
58
ƒ Error()
59
60
ERROR
61
ƒ Error()
62
Using SwitchMap in Angular
9 Comments / 6 minutes of reading / May 16, 2021
Angular Tap
Angular MergeMap
The Angular SwitchMap maps each value from the source observable into an inner observable, subscribes to it, and
then starts emitting the values from it. It creates a new inner observable for every value it receives from the Source.
Whenever it creates a new inner observable it unsubscribes from all the previously created inner observables.
Basically it switches to the newest observable discarding all other.
Table of Contents
Syntax
SwitchMap Example
SwitchMap Vs Map
SwitchMap switches to the most recent observable
Using SwitchMap in Angular
With Route Parameters
Angular Forms ValueChanges event
References
Syntax
The syntax of the SwitchMap operator is as shown below.
1
2 switchMap(project: (value: T, index: number) => O): OperatorFunction<T, ObservedValueOf<O>>
3
project: is a function that we use to manipulate the values emitted by the source observable. The project can accept
two arguments. one is value i.e. the value emitted by the source observable. The second argument is index number.
The index number starts from 0 for the first value emitted and incremented by one for every subsequent value
emitted. It is similar to the index of an array. The project function must return an observable.
SwitchMap Example
To use SwitchMap in Angular first we need to import it our Component or Service.
1
2 import { switchMap } from 'rxjs/operators';
3
The following code shows how to use SwitchMap in Angular. We have two observables srcObservable which
emits 1,2,3,4 & innerObservable which emits 'A','B','C','D'.
Table of Contents
Syntax
MergeMap Example
MergeMap Vs Map
MergeMap combines results of inner observable
Using MergeMap in Angular
Merging values from two or more HTTP Calls
Using ForkJoin with MergeMap
References
Syntax
The syntax of the MergeMap operator is as shown below.
1
2 mergeMap(project: (value: T, index: number) => O): OperatorFunction<T, ObservedValueOf<O>>
3
project: is a function that we use to manipulate the values emitted by the source observable. The project function
accepts two arguments. one is value i.e. the value emitted by the source observable. The second argument
is index number. The index number starts from 0 for the first value emitted and incremented by one for every
subsequent value emitted. It is similar to the index of an array. The project function must return an observable.
MergeMap Example
To use MergeMap in Angular first we need to import it our Component or Service.
1
2 import { mergeMap } from 'rxjs/operators';
3
The following code shows how to use MergeMap in Angular. We have two observables srcObservable which
emits 1,2,3,4 & innerObservable which emits 'A','B','C','D'.
1
2 let srcObservable= of(1,2,3,4)
3 let innerObservable= of('A','B','C','D')
4
5 srcObservable.pipe(
6 mergeMap( val => {
7 console.log('Source value '+val)
8 console.log('starting new observable')
9 return innerObservable
10 })
11 )
12 .subscribe(ret=> {
13 console.log('Recd ' + ret);
14 })
15
16
17 //Output
18 Source value 1
19 starting new observable
20 Recd A
21 Recd B
22 Recd C
23 Recd D
24 Source value 2
25 starting new observable
26 Recd A
27 Recd B
28 Recd C
29 Recd D
30 Source value 3
31 starting new observable
32 Recd A
33 Recd B
34 Recd C
35 Recd D
36 Source value 4
37 starting new observable
38 Recd A
39 Recd B
40 Recd C
41 Recd D
42
The Angular ConcatMap maps each value from the source observable into an inner observable, subscribes to it, and
then starts emitting the values from it replacing the original value. It creates a new inner observable for every value
it receives from the Source. It merges the values from all of its inner observables in the order in which they are
subscribed and emits the values back into the stream. Unlike SwitchMap, ConcatMap does not cancel any of its inner
observables. It is Similar to MergeMap except for one difference that it maintains the order of its inner observables.
Table of Contents
Syntax
ConcatMap Example
ConcatMap Vs Map
ConcatMap combines inner observable and keeps the order
Using ConcatMap in Angular
Merging values from two or more HTTP Calls
Using ForkJoin with ConcatMap
References
Syntax
The syntax of the concatMap operator is as shown below.
1
2 concatMap(project: (value: T, index: number) => O): OperatorFunction<T, ObservedValueOf<O>>
3
project: is a function that we use to manipulate the values emitted by the source observable. The project function
accepts two arguments. one is value i.e. the value emitted by the source observable. The second argument
is index number. The index number starts from 0 for the first value emitted and incremented by one for every
subsequent value emitted. It is similar to the index of an array. The project function must return an observable.
ConcatMap Example
To use concatMap in Angular first we need to import it our Component or Service.
1
2 import { concatMap } from 'rxjs/operators';
3
In the following code, we have two observables srcObservable which emits 1,2,3,4 & innerObservable which
emits 'A','B','C','D'.
1
2 let srcObservable= of(1,2,3,4)
3 let innerObservable= of('A','B','C','D')
4
5 srcObservable.pipe(
6 concatMap( val => {
7 console.log('Source value '+val)
8 console.log('starting new observable')
9 return innerObservable
10 })
11 )
12 .subscribe(ret=> {
13 console.log('Recd ' + ret);
14 })
15
16
17 //Output
18 Source value 1
19 starting new observable
20 Recd A
21 Recd B
22 Recd C
23 Recd D
24 Source value 2
25 starting new observable
26 Recd A
27 Recd B
28 Recd C
29 Recd D
30 Source value 3
31 starting new observable
32 Recd A
33 Recd B
34 Recd C
35 Recd D
36 Source value 4
37 starting new observable
38 Recd A
39 Recd B
40 Recd C
41 Recd D
42
The Angular ExhaustMap maps each value from the source observable into an inner observable, subscribes to it. It
then starts emitting the values from it replacing the original value. It then waits for the inner observable to finish. If it
receives any new values before the completion of the inner observable it ignores it. It receives a new value after
completion of the inner observable, then it creates a new inner observable. The whole process repeats itself until
the source observable is completes
Table of Contents
Syntax
ExhaustMap Example
ExhaustMap waits for the inner observable to finish
Using ExhaustMap in Angular
References
Syntax
The syntax of the exhaustMap operator is as shown below.
1
2 exhaustMap(project: (value: T, index: number) => O): OperatorFunction<T, ObservedValueOf<O>>
3
project: is a function that we use to manipulate the values emitted by the source observable. The project function
accepts two arguments. one is value i.e. the value emitted by the source observable. The second argument
is index number. The index number starts from 0 for the first value emitted and incremented by one for every
subsequent value emitted. It is similar to the index of an array. The project function must return an observable.
ExhaustMap Example
To use ExhaustMap in Angular first we need to import it our Component or Service.
1
2 import { exhaustMap} from 'rxjs/operators';
3
In the following code, we have two observables srcObservable which emits 1,2,3,4 & innerObservable which
emits 'A','B','C','D'.
The take, takeUntil, takeWhile & takeLast operators allow us to filter out the emitted values from the observable.
The take(n) emits the first n values, while takeLast(n) emits the last n values. The takeUntil(notifier) keeps emitting
the values until it is notified to stop. takeWhile(predicate) emits the value while values satisfy the predicate. All of
the stops emitting once done.
Table of Contents
Take
TakeUntil
TakeWhile
TakeWhile Vs Filter
TakeLast
References
Take
Take operator emits the first n number of values before completing. Any reminder values are ignored.
Syntax
take(n)
Where n is the maximum number of values to emit.
If the source emits more than n values, then take emits only n values and completes
If the source emits less than n number of values, then take emits all of them before completing.
Example
app.component.ts
1
2 import { Component, VERSION } from "@angular/core";
3 import { of } from "rxjs";
4 import { take } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12
13 obs = of(1, 2, 3, 4, 5).pipe(take(2));
14
15 ngOnInit() {
16 this.obs.subscribe(val => console.log(val));
17 }
18 }
19
20
21
22 ****Console ******
23 1
24 2
25
Source Code
1
2
3 export class AppComponent {
4
5 takeFive = interval(1000).pipe(take(5));
6
7 ngOnInit() {
8 this.takeFive.subscribe(val => console.log(val));
9 }
10 }
11
12
13 ****Console ******
14 0
15 1
16 2
17 3
18 4
19
TakeUntil
The takeUntil operator returns an Observable that emits value from the source Observable until
the notifier Observable emits a value.
Syntax
1
2 TakeUntil(notifier: Observable): Observable
3
We must pass a notifier observable as the argument to the TakeUntil Operator
TakeUntil emits the values from the Source Observable as long as it does not receive any value from the notifier
observable
When the notifier emits a value, the TakeUntil completes the Source observable.
If the notifier completes without emitting any value, then the TakeUntil keeps emitting values from the source and
completes when the source completes.
Example
In the example below, we create a notifier observable
1
2 notifier= new Subject();
3
The notifier observable emits a value , when use clicks on the stop button.
1
2 stopObs() {
3 this.notifier.next();
4 this.notifier.complete();
5 }
6
Use the takeUntil in the source observable as shown below
1
2 obs = interval(1000).pipe(takeUntil(this.notifier));
3
Run the app. The source observable stops when you click on stop button.
app.component.ts
1
2 import { Component, VERSION } from "@angular/core";
3 import { of, interval, Subject, Observable } from "rxjs";
4 import { take, takeUntil, tap } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12 notifier = new Subject();
13
14 obs = interval(1000).pipe(takeUntil(this.notifier));
15
16 ngOnInit() {
17 this.obs.subscribe(val => console.log(val));
18 }
19
20 stopObs() {
21 this.notifier.next();
22 this.notifier.complete();
23 }
24 }
25
Source Code
app.component.html
1
2 <h1>TakeUntil Example</h1>
3
4 <button (click)="stopObs()">Stop</button>
5 <br>
6
7
Source Code
One of the use cases of takeUntil is to automatically unsubscribe all the observables. You can refer to it from the
tutorial on Unsubscribing from an observable.
TakeWhile
TakeWhile operator will keep emitting the value from the source observable as long as they pass the given condition
(predicate). When it receives a value that does not satisfy the condition it completes the observable. No further
values are emitted even if they satisfy the condition.
Syntax
1
2 takeWhile(predicate: function(value, index): boolean,
3 inclusive?: boolean): Observable
4
Where predicate is the condition.
If inclusive is true, then the emits the value, which does not pass the condition before terminating the observable.
Example
In the code below takeWhile tests the condition val < 3 against the incoming values. When it receives the value 3,
which does not satisfy the condition, the observable completes. It does not emit any further values although the
stream still has values that satisfy the condition.
1
2 import { Component, VERSION } from "@angular/core";
3 import { of, interval, Subject, Observable } from "rxjs";
4 import { take, takeUntil, takeWhile, tap } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12 obs = of(1, 2, 3, 1, 2, 3, 1, 2, 3)
13 .pipe(
14 takeWhile(val => val < 3)
15 );
16
17 ngOnInit() {
18 this.obs.subscribe(val => console.log(val));
19 }
20 }
21
22
23 *** Console ***
24 1
25 2
26
27
Source Code
With inclusive is set to true, takewhile also emits the value 3 before completing the observable.
1
2 export class AppComponent {
3 obs = of(1, 2, 3, 1, 2, 3, 1, 2, 3)
4 .pipe(
5 takeWhile(val => val < 3, true)
6 );
7
8 ngOnInit() {
9 this.obs.subscribe(val => console.log(val));
10 }
11 }
12
13 *** Console ***
14 1
15 2
16 3
17
Source Code
Example
1
2 evenNumbers = of(2, 4, 6, 3, 8)
3 .pipe(takeWhile(n => n % 2 == 0))
4 .subscribe(val => console.log(val));
5
6 **Console ***
7 2
8 4
9 6
10
11 //8 is not emitted
12
TakeWhile Vs Filter
Both takeWhile & filter uses the condition to filter out the incoming stream. Both allows only the matching values to
pass through discarding the others.
The difference is that takeWhile discards the rest of the stream, when it receives the first value that does not satisfy
the condition (If the inclusive is set to true, then it also emits the last value even when it does not satisfy the
condition). The filter operator never stops the observable.
The following example, filter operator does not stop when it receives the value 3. But it discards it and continues
further until the stream itself completes.
Example
1
2 obs = of(1, 2, 3, 1, 2, 3, 1, 2, 3)
3 .pipe(
4 filter(val => val < 3, true)
5 );
6
7 ngOnInit() {
8 this.obs.subscribe(val => console.log(val));
9 }
10
11
12 ***Console ****
13 1
14 2
15 1
16 2
17 1
18 2
19
Source Code
TakeLast
TakeLast operator emits the last n number of values from the source observable.
Syntax
1
2 takeLast<T>(n: number)
3
Where n is the maximum number of values to emit.
To know the last n number of values, the TakeLast needs to wait for the source to complete. Hence if the source
never completes, then TakeLast will never emit a value.
When the stream completes, the takeLast will
emits the last n number of values
if the source emits less than the n number of values then it emits all of them
stream completes immediatly
Example
1
2 import { Component, VERSION } from "@angular/core";
3 import { of, range, Observable } from "rxjs";
4 import { takeLast } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12 obs = range(1, 100).pipe(takeLast(3));
13
14 ngOnInit() {
15 this.obs.subscribe(val => console.log(val));
16 }
17 }
18
19 ***Console****
20 98
21 99
22 100
23
Source Code
References
take
takeUntil
takeWhile
takeLast
First, Last & Single Operator in Angular Observable
1 Comment / 5 minutes of reading / January 26, 2021
Take, TakeUntil, TakeWhile, TakeLast
Skip, SkipUntil, SkipWhile & SkipLast
In the tutorial, let us learn the First, Last & Single RxJs operators in Angular Observable. All three operators use the
predicate (condition) to check the values of the source observable. The first emits the first matching value, the Last
emits the last matching value & the Single emits only if a single value matches the predicate.
Table of Contents
First Operator
First Vs Take(1)
Last Operator
Last Vs TakeLast(1)
Single
References
First Operator
The first operator emits the first value that meets the condition. If no condition is specified, then it will emit the first
value it receives.
Syntax
1
first<T, D>(predicate?: (value: T, index: number, source: Observable<T>) => boolean, defaultValue?: D) :
2
OperatorFunction<T, T | D>
3
Where
predicate: is the condition to match
defaultValue: is the value to emit if no value matches the condition
Emits the first value if no predicate is present
Emits the first matching value if the predicate is present
Closes the stream after emitting a value
If the source completes before emitting any matching value, then it raises the error notification.
Example
In the following example, we create an observable using the of operator. The first operator here emits the first value
it receives i.e 1 and then it completes.
1
2 import { Component, VERSION } from "@angular/core";
3 import { timer, interval, of } from "rxjs";
4 import { first } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12 src = of(1, 2, 3, 4, 5).pipe(first());
13
14 id = Date.now();
15
16 constructor() {}
17
18 ngOnInit() {
19 console.log("Component Created " + this.id);
20
21 this.src.subscribe(value => {
22 console.log(value);
23 });
24 }
25 }
26
27
28 *** Result ****
29 1
30
Source Code
Emits the first value that matches
1
2 src = of(1, 2, 3, 4, 5).pipe(first(val => val > 3));
3
4
5 **Result**
64
7
Source Code
The following code returns an error as no value matches the condition.
1
2 src = of(1, 2, 3, 4, 5).pipe(first(val => val > 10));
3
4
5 ***Error
6 no elements in sequence
7
Source Code
But first with the default value, will emit the default value if no value matches the condition.
1
2 src = of(1, 2, 3, 4, 5).pipe(first(val => val > 10,100));
3
4
5 ***Console**
6 100
7
The following also results in an error, as the source does not emit any values
1
2 src = of().pipe(first());
3
4
5 ***Error
6 no elements in sequence
7
The following emits the default value 100
1
2 src = of().pipe(first(val => true, 100));
3
4
5 ***Console
6 100
7
First Vs Take(1)
The first() (without condition & default value) and take(1) returns the first value they receive from the source and
closes the observable.
But they have a difference in behavior when the source does not emit anything. The first() send an error notification,
while take(1) will not emit anything, but closes the observable.
Last Operator
The last operator emits the last value that meets the condition. If no condition is specified, then it will emit the last
value it receives.
Syntax
1
last<T, D>(predicate?: (value: T, index: number, source: observable<T>) => boolean, defaultValue?:
2
D) :OperatorFunction<T, T | D>
3
Waits for the source to complete before emitting the value
Emits the last value if no predicate is present
Emits the last matching value if the predicate is present
Closes the stream after emitting a value
If the source completes before emitting any matching value, then It raises the error notification.
Example
In the following example, we create an observable using the of operator. The last operator here emits the last value
it receives i.e 5 and then it completes.
1
2 import { Component, VERSION } from "@angular/core";
3 import { timer, interval, of } from "rxjs";
4 import { last } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12 src = of(1, 2, 3, 4, 5).pipe(last());
13
14 id = Date.now();
15
16 constructor() {}
17
18 ngOnInit() {
19 console.log("Component Created " + this.id);
20
21 this.src.subscribe(value => {
22 console.log(value);
23 });
24 }
25 }
26
27 **Console **
28 5
29
Source Code
Emits the last value that matches the predicate
1
2 src = of(1, 2, 3, 4, 5).pipe(last(val => val < 3));
3
4
5 ***Console**
62
7
Source Code
Returns an error as no value matches the condition.
1
2 src = of(1, 2, 3, 4, 5).pipe(last(val => val < 0));
3
4
5 *** Console *****
6 ERROR
7 Error: no elements in sequence
8
9
But with a default value, it will emit the default value if no value matches the condition.
1
2 src = of(1, 2, 3, 4, 5).pipe(last(val => val < 0,0));
3
4
5 ***Console**
6 100
7
The following also results in an error, as the source does not emit any values
1
2 src = of().pipe(last());
3
4 ***Error
5 no elements in sequence
6
The following emits the default value 100
1
2 src = of().pipe(last(val => true, 100));
3
4
5 ***Console
6 100
7
Last Vs TakeLast(1)
The last() (without condition & default value) and takeLast(1) returns the last value they receive from the source
observable.
But they have a difference in behavior when the source does not emit anything. The last() send an error notification,
while takeLast(1) will not emit anything, but closes the observable.
Single
The Single operator emits a single value that meets the condition.
The Single operator waits for the source to complete before emitting the value
Emits a single value that meets the condition
If more than one value satisfies the condition, then it raises an error notification
If no value satisfies the condition, then it emits the value undefined
Raises the error notification, if the source does not emit any value.
Syntax
1
single<T>(predicate?: (value: T, index: number, source: Observable<T>) => boolean):
2
MonoTypeOperatorFunction<T>
3
Where
predicate is the condition
Examples
Emits 3 as it matches the condition.
1
2 src = of(1, 2, 3, 4, 5).pipe(single(val => val == 3));
3
4
5 **Console
63
7
Source Code
Waits for the observable to finish. Hence the following will never emit a value.
1
2 src = interval(1000).pipe(single(val => val == 3));
3
4 **Console*
5
Raises error notification as there are more than one value that satisfies the condition.
1
2 src = of(1, 2, 3, 4, 3).pipe(single(val => val == 3));
3
4
5 **Console**
6 ERROR
7 Sequence contains more than one element
8
9
If the source does not emit any matching values, then the Single operator emits undefined. Note that it does not
emit error notification.
1
2 src = of(1, 2, 3, 4, 3).pipe(single(val => val == 5));
3
4 *Console*
5 undefined
6
Single without any predicate matches all values. Hence the error.
1
2 src = of(1, 2, 3, 4, 3).pipe(single());
3
4 ***Console***
5 ERROR
6 Sequence contains more than one element
7
Source contains single value and Single without predicate. Emits the value
1
2 src = of(1).pipe(single());
3
4 **Console**
51
6
Source is empty, Hence it raises error notification.
1
2 src = of().pipe(single());
3
4
5 **Console***
6 ERROR
7 Error: no elements in sequence
8
Skip, SkipUntil, SkipWhile & SkipLast Operators in Angular
1 Comment / 4 minutes of reading / January 26, 2021
First, Last & Single
Scan & Reduce
The skip operators in Angular skips the values from the source observable based on a condition. The Skip, SkipUntil,
SkipWhile skips the values from the start of the source. The SkipLast Operator skips elements from the end of the
source.
Table of Contents
Skip
Skip Example
SkipWhile
SkipWhile Example
Filter Vs SkipWhile
SkipUntil
SkipUntil Example
SkipLast
SkipLast Example
SkipLast delays the values
Reference
Skip
The skip operator skips the first count number of values from the source observable and returns the rest of the
source as an observable
Syntax
1
2 skip<T>(count: number): MonoTypeOperatorFunction<T>
3
Skip Example
The example below skip(5) ignores the first 5 values & returns the rest of the observable as it is.
1
2 import { Component } from "@angular/core";
3 import { skip } from "rxjs/operators";
4 import { interval, of } from "rxjs";
5
6 @Component({
7 selector: "my-app",
8 template: `
9 <h1>Skip Example</h1>
10
11 <br />
12 <br />
13 `,
14 styleUrls: ["./app.component.css"]
15 })
16 export class AppComponent {
17 ngOnInit() {
18 of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
19 .pipe(
20 skip(5),
21 )
22 .subscribe(val => console.log(val));
23 }
24 }
25
26
27 ** Console **
28 6
29 7
30 8
31 9
32 10
33
Source Code
SkipWhile
The SkipWhile operator skips values from the source observable as long as the specified condition is true. But once
the condition becomes false, it starts to emit the values and continues to do so even if the condition becomes true
again.
Syntax
1
2 skipWhile<T>(predicate: (value: T, index: number) => boolean): MonoTypeOperatorFunction<T>
3
SkipWhile Example
1
2 of( 2, 4, 5, 6, 7, 8, 9, 10)
3 .pipe(
4 skipWhile(val => val % 2==0),
5 )
6 .subscribe(val => console.log(val));
7
8
9 **Console**
10 5
11 6
12 7
13 8
14 9
15 10
16
Filter Vs SkipWhile
The Filter operator and SkipWhile operator uses a predicate to filter out the values.
The SkipWhile skips the values if the predicate is true, While the filter emits the values if the predicate is true.
Once the predicate becomes false, the SkipWhile stops using the predicate and emits all the remaining values.
The filter keeps using the predicate to filter out the remaining values.
Filter Example
1
2 import { Component } from "@angular/core";
3 import { filter } from "rxjs/operators";
4 import { interval, of, timer } from "rxjs";
5
6 @Component({
7 selector: "my-app",
8 template: `
9 <h1>Filter Example</h1>
10 `,
11 styleUrls: ["./app.component.css"]
12 })
13 export class AppComponent {
14 ngOnInit() {
15 of(2, 4, 5, 6, 7, 8, 9, 10)
16 .pipe(
17 filter(val => {
18 return val %2==0;
19 }),
20 )
21 .subscribe(val => console.log(val));
22 }
23 }
24
25
26 ***Console***
27 2
28 4
29 6
30 8
31 10
32
SkipUntil
The SkipUntil operator skips the values from the source observable as long as the second observable does not emit
any value. But once the second observable emits a value, it starts to emit the values and continues to do so as long
as the source emits values.
It is very similar to SkipWhile except that the condition is provided by another observable.
Syntax
1
2 skipUntil<T>(notifier: Observable<any>): MonoTypeOperatorFunction<T>
3
SkipUntil Example
The interval creates an observable, which emits a value for every 1000 ms. The SkipUntil operator uses the
timer(6000) observable, which emits a value after 6000ms. Hence the SkipUntil skips the first 5 values (0 to 4) and
starts to emit the values from 5
1
2 interval(1000)
3 .pipe(
4 skipUntil(timer(6000)),
5 )
6 .subscribe(val => console.log(val));
7
8 ***Console **
9 5
10 6
11 7
12 8
13 ....
14
Source Code
SkipLast
The SkipLast operator skips the last count number of values from the source observable and returns the rest of the
source as an observable.
It is exactly opposite of skip(count), which skips the first count number of values
Syntax
1
2 skipLast<T>(count: number): MonoTypeOperatorFunction<T>
3
SkipLast Example
In the following example, the skiplast(5) will skip the last 5 values (i.e 6 to 10)
1
2 of(1,2,3,4,5,6,7,8,9,10)
3 .pipe(
4 skipLast(5)
5 )
6 .subscribe(val => console.log(val));
7
8 **Console*
9 1
10 2
11 3
12 4
13 5
14
Source Code
SkipLast delays the values
SkipLast(count) waits until it receives the count number of values from the source, before it starts emitting the
values.
In the above example, the skipLast does not emit any values till the values 5. When it receives the value 6, it emits
the value 1. You can see it by using the tap operator.
1
2 of(1,2,3,4,5,6,7,8,9,10)
3 .pipe(
4 tap(val => {
5 console.log("tap " + val);
6 }),
7 skipLast(5)
8 )
9 .subscribe(val => console.log(val));
10
11
12 **Console**
13 tap 1
14 tap 2
15 tap 3
16 tap 4
17 tap 5
18 tap 6
19 1
20 tap 7
21 2
22 tap 8
23 3
24 tap 9
25 4
26 tap 10
27 5
28
The Scan & Reduce operators in Angular
Leave a Comment / 5 minutes of reading / January 26, 2021
Skip, SkipUntil, SkipWhile & SkipLast
Debounce & DebounceTime
The Scan & Reduce Operators in Angular applies an accumulator function on the values of the source observable.
The Scan Operator returns all intermediate results of the accumulation, while Reduce only emits the last result. Both
also use an optional seed value as the initial value.
Table of Contents
Scan in Angular
Scan Example
Reduce in Angular
Reduce Example
References
Scan in Angular
The scan operator applies an accumulator function over the values emitted by the source Observableble sequentially
and emits each value.
Syntax
1
2 scan<T, R>(accumulator: (acc: R, value: T, index: number) => R, seed?: T | R): OperatorFunction<T, R>
3
Where
accumulator is the function, that is called on each source value
seed is the initial accumulation value (optional)
The accumulator function gets three argument.
acc is the accumulator variable where the values are accumulated.
value comes from the source observable,
index of the value.
The initial value for the acc comes from the seed.
When the first value arrives from the source, the scan operator invokes the accumulator function on these two
variables and emits the result.
When the second value arrives from the source, the result of the previous step becomes the input ( acc ). The scan
emits a new result, which then becomes the input for the third emission.
This cycle continues till the stream completes.
Scan Example
In the example below (acc, value) => acc + value is the accumulator function. Seed is 0.
1
2 import { Component } from "@angular/core";
3 import { map, scan } from "rxjs/operators";
4 import { interval, of } from "rxjs";
5
6 @Component({
7 selector: "my-app",
8 template: `
9 <h1>Scan Operator Example</h1>
10 `,
11 styleUrls: ["./app.component.css"]
12 })
13 export class AppComponent {
14 reTryCount = 0;
15
16 ngOnInit() {
17 of(1, 2, 3, 4, 5)
18 .pipe(scan((acc, value) => acc + value, 0))
19 .subscribe(
20 val => console.log(val),
21 e => console.log(e),
22 () => console.log("Complete")
23 );
24 }
25 }
26
27
28 ***Console***
29
30 1
31 3
32 6
33 10
34 15
35 Complete
36
Source Code
The value for acc starts with the seed value i.e. 0. The variable value gets the value 1, which is the first value emitted
by the source. The scan operator runs the accumulator function (acc + value = 1) and emits the result.
The result of the previous accumulator function becomes the input (acc) of the next scan. It is added to the next
value (i. e. 2) emitted from the source and the result becomes 3.
This will continue until we reach the end of sequence
In the following code, we change the seed to 10. Now the accumulator starts with 10 instead of 0.
1
2 of(1, 2, 3, 4, 5)
3 .pipe(scan((acc, value) => acc + value, 10))
4 .subscribe(
5 val => console.log(val),
6 e => console.log(e),
7 () => console.log("Complete")
8 );
9
10 *** Result ***
11 11
12 13
13 16
14 20
15 25
16 Complete
17
18
Combining as Arrays
1
2 of(1, 2, 3, 4, 5)
3 .pipe(scan((acc, value) => [...acc, value], []))
4 .subscribe(
5 val => console.log(val),
6 e => console.log(e),
7 () => console.log("Complete")
8 );
9
10 *** Console ***
11 [1]
12 [1, 2]
13 [1, 2, 3]
14 [1, 2, 3, 4]
15 [1, 2, 3, 4, 5]
16
Source Code
Tracking Button Clicks
1
2 import { Component, ElementRef, ViewChild } from "@angular/core";
3 import { map, scan } from "rxjs/operators";
4 import { fromEvent, interval, of, Subscription } from "rxjs";
5
6 @Component({
7 selector: "my-app",
8 template: `
9 <h1>Scan Operator Example</h1>
10
11 <button #btn>Button</button>
12 `,
13 styleUrls: ["./app.component.css"]
14 })
15 export class AppComponent {
16 @ViewChild("btn", { static: true }) button: ElementRef;
17 sub: Subscription;
18
19 ngAfterViewInit() {
20 this.sub = fromEvent(this.button.nativeElement, "click")
21 .pipe(scan((acc, value) => acc + 1, 0))
22 .subscribe(val => console.log("You clicked " + val + " times"));
23 }
24
25 ngOnDestroy() {
26 this.sub.unsubscribe();
27 }
28 }
29
30
Source Code
Reduce in Angular
The Reduce operator applies an accumulator function over the values emitted by the source Observation
sequentially and returns the accumulated result when the source completes.
The Reduce operator behaves exactly like the scan operator, except for the following differences
It does not return the intermediate results.
It returns only after the source completes.
Reduce Example
The following example is similar to the scan example above. The only difference is that you will not see the
intermediate results i.e. 1, 3, 6 10.
1
2 ngOnInit() {
3 of(1, 2, 3, 4, 5)
4 .pipe(reduce((acc, value) => acc + value, 0))
5 .subscribe(
6 val => console.log(val),
7 e => console.log(e),
8 () => console.log("Complete")
9 );
10 }
11
12
13 ** Console **
14
15 15
16 Complete
17
Source Code
Combining as Arrays
1
2 ngOnInit() {
3 of(1, 2, 3, 4, 5)
4 .pipe(reduce((acc, value) => [...acc, value], []))
5 .subscribe(
6 val => console.log(val),
7 e => console.log(e),
8 () => console.log("Complete")
9 );
10 }
11
12 ** Console ***
13 [1, 2, 3, 4, 5]
14 Complete
15
Source Code
Tracking Button Clicks
The Reduce operator emits only if the observable completes. Hence in the Tracking button click example, just
replacing the scan with the reduce will not work.
In the following example, we create a new observable using the Subject and emit the click event using the event
binding. This allows us to raise the complete notification.
1
2 import { Component, ElementRef, ViewChild } from "@angular/core";
3 import { map, reduce, scan } from "rxjs/operators";
4 import { fromEvent, interval, of, Subject, Subscription } from "rxjs";
5
6 @Component({
7 selector: "my-app",
8 template: `
9 <h1>Reduce Operator Example</h1>
10
11 <button (click)="clickMe($event)">Click Me</button>
12 <br />
13 <br />
14 <br />
15 <button (click)="startCounting($event)">Sart</button>
16
17 <button (click)="stopCounting()">Stop</button>
18 `,
19 styleUrls: ["./app.component.css"]
20 })
21 export class AppComponent {
22 clickStream: Subject<Event>;
23 sub: Subscription;
24
25 ngOnInit() {}
26
27 clickMe(event: Event) {
28 console.log("Clicked");
29 if (this.clickStream) this.clickStream.next(event);
30 }
31
32 startCounting(event: Event) {
33 this.clickStream = new Subject<Event>();
34 this.sub = this.clickStream
35 .asObservable()
36 .pipe(reduce((acc, value) => acc + 1, 0))
37 .subscribe(val => console.log("You clicked " + val + " times"));
38 }
39
40 stopCounting() {
41 this.clickStream.complete();
42 }
43
44 ngOnDestroy() {}
45 }
46
47
DebounceTime & Debounce in Angular
Leave a Comment / 3 minutes of reading / January 26, 2021
Scan & Reduce
Delay & DelayWhen
DebounceTime & Debounce are the Angular RxJs Operators. Both emit values from the source observable, only after
a certain amount of time has elapsed since the last value. Both emit only the latest value and discard any
intermediate values. In this tutorial, we will learn how to use both DebounceTime & Debounce with examples.
Table of Contents
Use Case of Debounce Operators
DebounceTime
How it works
DebounceTime Example
Sending HTTP GET Request
Debounce
Debounce Example
Reference
Use Case of Debounce Operators
The typeahead/autocomplete fields are one of the most common use cases for Debounce Operators.
As the user types in the typeahead field, we need to listen to it and send an HTTP request to the back end to get a list
of possible values. If we send HTTP requests for every keystroke, we end up making numerous unneeded calls to the
server.
By using the Debounce Operators, we wait until the user pauses typing before sending an HTTP Request. This will
eliminates unnecessary HTTP requests.
DebounceTime
The Debouncetime emits the last received value from the source observable after a specified amount of time has
elapsed without any other value appearing on the source Observable
Syntax
1
2 debounceTime<T>(dueTime: number, scheduler: SchedulerLike = async): MonoTypeOperatorFunction<T>
3
Where dueTime The timeout duration in milliseconds.
How it works
First, we assign a timeout duration (dueTime) to the Debouncetime operator.
The Debouncetime operator starts counting time after it receives a value.
If the source observable emits a value before the timeout duration, then counting is reset to zero & started again.
When the timeout duration elapses the operator emits the last value and the counting stops.
Counting starts again when the operators receive another value.
DebounceTime Example
The following DebounceTime example shows how to use the operator to listen for input field changes
1
2 import { Component, VERSION } from "@angular/core";
3 import { FormControl, FormGroup } from "@angular/forms";
4 import { Observable, Subscription } from "rxjs";
5 import { debounceTime } from "rxjs/operators";
6
7 @Component({
8 selector: "my-app",
9 template: `
10 <form [formGroup]="mform">Name: <input formControlName="name" /></form>
11 `,
12 styleUrls: ["./app.component.css"]
13 })
14 export class AppComponent {
15
16 mform: FormGroup = new FormGroup({
17 name: new FormControl()
18 });
19
20 obs:Subscription;
21
22 ngOnInit() {
23 this.obs=this.mform.valueChanges
24 .pipe(debounceTime(500))
25 .subscribe(data => console.log(data));
26 }
27
28 ngOnDestroy() {
29 this.obs.unsubscribe();
30 }
31 }
32
Souce Code
Sending HTTP GET Request
The following example shows how you can send an HTTP GET Request using switchMap & debounceTime.
1
2 ngOnInit() {
3 this.obs=this.mform.valueChanges
4 .pipe(
5 debounceTime(500),
6 switchMap(id => {
7
8 console.log(id)
9 return this.http.get(url)
10
11 })
12 )
13 .subscribe(data => console.log(data));
14 }
15
Debounce
The Debounce operator is similar to the DebounceTime operator, but another observable will provide the time span.
By Using the Debounce, we can set the time span dynamically.
Debounce Example
The following example works the same as the previous example. Instead of using the hardcoded time span, we
create a new observable using the interval operator.
1
2 import { Component, VERSION } from "@angular/core";
3 import { FormControl, FormGroup } from "@angular/forms";
4 import { debounce } from "rxjs/operators";
5 import { interval, Subscription } from "rxjs";
6
7 @Component({
8 selector: "my-app",
9 template: `
10 <form [formGroup]="mform">Name: <input formControlName="name" /></form>
11 `,
12 styleUrls: ["./app.component.css"]
13 })
14 export class AppComponent {
15 mform: FormGroup = new FormGroup({
16 name: new FormControl()
17 });
18
19 obs:Subscription
20
21 ngOnInit() {
22 this.obs=this.mform.valueChanges
23 .pipe(debounce(() => interval(500)))
24 .subscribe(data => console.log(data));
25 }
26
27 ngOnDestroy() {
28 this.obs.unsubscribe()
29 }
30
31 }
32
33
Source Code
You can also customize the delay. In the following example, we increase the delay by 100ms after every keystroke.
1
2
delay = 500;
3
4
obs: Subscription;
5
6
ngOnInit() {
7
this.obs = this.mform.valueChanges
8
.pipe(
9
debounce(() => {
10
this.delay = this.delay + 100;
11
console.log(this.delay);
12
return interval(this.delay);
13
})
14
)
15
.subscribe(data => console.log(data));
16
}
17
Delay & DelayWhen in Angular
Leave a Comment / 3 minutes of reading / January 26, 2021
DebounceTime & Debounce
ThrowError
Delay & DelayWhen Operators in Angular delays the emission of values from the source observable. The Delay
operator delays by a given timeout or until a given Date. The DelayWhen delays until it receives a notification from
another observable.
Table of Contents
Delay
Delay Example
Delay Each item
Passing Date to Delay Operator
DelayWhen
DelayWhen Example
References
Delay
Delays the emission of items from the source Observable by a given timeout or until a given Date.
Syntax
1
2 delay<T>(delay: number | Date, scheduler: SchedulerLike = async): MonoTypeOperatorFunction<T>
3
Where
delay is the delay in milliseconds or a Date until which the emission of the source items are delayed
Note that delay delays the entire observable and not the individual items.
Delay Example
In the following example, we add a delay of 1000ms. After 1000ms all the values appear instantly.
1
2 import { Component, VERSION } from "@angular/core";
3 import { of } from "rxjs";
4 import { delay, map, tap } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 template: `
9 <h1>Delay & DelayWhen Example</h1>
10 `,
11 styleUrls: ["./app.component.css"]
12 })
13 export class AppComponent {
14 ngOnInit() {
15 of(1, 2, 3, 4, 5)
16 .pipe(
17 tap(val => console.log("Before " + val)),
18 delay(1000)
19 )
20 .subscribe(
21 val => console.log(val),
22 e => console.log(e),
23 () => console.log("Complete")
24 );
25 }
26 }
27
28
29 Before 1
30 Before 2
31 Before 3
32 Before 4
33 Before 5
34
35 1
36 //Appears after a delay of 1000ms
37 2
38 3
39 4
40 5
41 Complete
42
Source Code
Delay Each item
The following code uses concatMap with delay operator to add delay between each emission.
1
2
3 of(1, 2, 3, 4, 5)
4 .pipe(
5 tap(val => console.log("Before " + val)),
6 concatMap(item => of(item).pipe(delay(1000)))
7 )
8 .subscribe(
9 val => console.log(val),
10 e => console.log(e),
11 () => console.log("Complete")
12 );
13
14
15 *** Console ****
16
17 Before 1
18 Before 2
19 Before 3
20 Before 4
21 Before 5
22
23 1
24 2
25 3
26 4
27 5
28 Complete
29
Source Code
Passing Date to Delay Operator
Instead of delay in milliseconds, we can also pass the date. Operator time shifts the start of the Observable
execution until the given date occurs.
In the following example, we add a 5 second to the current date and pass it to the delay operator.
1
2 import { Component, VERSION } from "@angular/core";
3 import { of } from "rxjs";
4 import { delay, tap } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 template: `
9 <h1>Delay & DelayWhen Example</h1>
10 `,
11 styleUrls: ["./app.component.css"]
12 })
13 export class AppComponent {
14 dt = new Date();
15
16 ngOnInit() {
17 console.log(this.dt);
18
19 this.dt.setSeconds(this.dt.getSeconds() + 5);
20 console.log(this.dt);
21
22 of(1, 2, 3, 4, 5)
23 .pipe(
24 tap(val => console.log("Tap " + val)),
25 delay(this.dt)
26 )
27 .subscribe(
28 val => console.log(val),
29 e => console.log(e),
30 () => console.log("Complete")
31 );
32 }
33 }
34
35
36
Source Code
DelayWhen
Delays the emission of items from the source observable by a given time span determined by the emissions of
another observable.
DelayWhen Example
The DelayWhen triggers when the timer observable emits an value after 1000 ms.
1
2 of(1, 2, 3, 4, 5)
3 .pipe(
4 tap(val => console.log("Before " + val)),
5 delayWhen(() => timer(1000))
6 )
7 .subscribe(
8 val => console.log(val),
9 e => console.log(e),
10 () => console.log("Complete")
11 );
12
13
14 *** Console ****
15 Before 1
16 Before 2
17 Before 3
18 Before 4
19 Before 5
20 1
21 2
22 3
23 4
24 5
25 Complete
26
In the following example, we create notification observable using Subject and use it in the DelayWhen Operator. We
emit the notification when the users click on a button. The DelayWhen waits until the notification before emitting
the values
1
2
import { Component, VERSION } from "@angular/core";
3
import { interval, of, Subject, timer } from "rxjs";
4
import { concatMap, delay, delayWhen, map, tap } from "rxjs/operators";
5
6
@Component({
7
selector: "my-app",
8
template: `
9
<h1>Delay & DelayWhen Example</h1>
10
11
<button (click)="emit()">Emit</button>
12
`,
13
styleUrls: ["./app.component.css"]
14
})
15
export class AppComponent {
16
click$ = new Subject<Event>();
17
18
ngOnInit() {
19
of(1, 2, 3, 4, 5)
20
.pipe(
21
tap(val => console.log("Before " + val)),
22
delayWhen(() => this.click$.asObservable())
23
)
24
.subscribe(
25
val => console.log(val),
26
e => console.log(e),
27
() => console.log("Complete")
28
);
29
}
30
31
emit() {
32
this.click$.next();
33
}
34
35
}
36
37
Using ThrowError in Angular Observable
Leave a Comment / 6 minutes of reading / January 26, 2021
Delay & DelayWhen
CatchError
Angular ThrowError operator returns an observable, which on subscription immediately errors out. It does not emit
any results.
Table of Contents
ThrowError
Throw Error Vs ThrowError
Throw Error Example
ThrowError
Using ThrowError
Using with catchError
Using it with MergeMap
References
ThrowError
ThrowError creates a new observable. Hence we must subscribe to it. The following example creates an ThrowError
observable and then subscribes to it.
1
2 import { Component, VERSION } from "@angular/core";
3 import { Observable, of, from, throwError } from "rxjs";
4 import { map, catchError } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12 name = "Angular " + VERSION.major;
13
14 obs = throwError("Error From ThrowError observable");
15
16 ngOnInit() {
17 this.obs.subscribe(
18 el => {
19 console.log("Value Received :" + el);
20 },
21 err => {
22 console.log("Error caught at Subscriber :" + err);
23 },
24 () => console.log("Processing Complete")
25 );
26 }
27 }
28
29
30
31 ****Console Window
32
33 Error caught at Subscriber: Error From ThrowError observable
34
Source Code
First, we create an observable using throwError. The first argument to the throwError is the error object. This error
object is passed to the consumers when it raises the error notification.
1
2 obs = throwError("Error From ThrowError observable")
3
We, subscribe to it in the ngOnInit method.
1
2 this.obs.subscribe(
3
4
The observable immediately raises the error notification and completes. The error callback is invoked and we will see
the error message in the console window.
1
2 err => {
3 console.log("Error caught at Subscriber :" + err);
4 },
5
6
Throw Error Vs ThrowError
It is very easy confuse between the Throw Error With ThrowError.
Throw Error throws an error. It is a JavaScript construct and is not part of the RxJs. We need to use the try/catch
block to catch the errors thrown from the Throw Error. The RxJS uses the try/catch block to catch any errors thrown
from the observables. And when they catch one, they emit an error notification (raises the error callback), and then
the observable stops.
ThrowError does not throw errors like throw Error. It returns a new observable, which emit an error notification
(raises the error callback), and then stops.
Throw Error Example
1
2 import { Component, VERSION } from "@angular/core";
3 import { Observable, of, from, throwError } from "rxjs";
4 import { map, catchError } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12
13
14 srcArray = from([1, 2, "A", 4]);
15
16 obs = this.srcArray.pipe(
17 map(val => {
18 let result = (val as number) * 2;
19 if (Number.isNaN(result)) {
20 console.log("Error in the observable");
21 throw Error("Not a Number");
22 }
23 return result;
24 })
25 );
26
27 ngOnInit() {
28 this.obs.subscribe(
29 el => {
30 console.log("Value Received :" + el);
31 },
32 err => {
33 console.log("Error caught at Subscriber :" + err);
34 },
35 () => console.log("Processing Complete.")
36 );
37 }
38 }
39
40
41 ***Console ****
42
43 Value Received :2
44 Value Received :4
45 Error in the observable
46 Error caught at Subscriber :Error: Not a Number
47
Source Code
The observable emits values 2 & 4.
When map operators receive the value A it uses throw Error to throw an error. The observable catches this error and
raises the error notification and terminates.
The last value 8 is never emitted.
ThrowError
Now, let us replace the throw Error with return throwError
1
2 import { Component, VERSION } from "@angular/core";
3 import { Observable, of, from, throwError } from "rxjs";
4 import { map, catchError } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12 name = "Angular " + VERSION.major;
13
14 srcArray = from([1, 2, "A", 4]);
15
16 obs = this.srcArray.pipe(
17 map(val => {
18 let result = (val as number) * 2;
19 if (Number.isNaN(result)) {
20 console.log("Error in the observable");
21 return throwError("Not a Number");
22 }
23 return result;
24 })
25 );
26
27 ngOnInit() {
28 this.obs.subscribe(
29 (el: any) => {
30 console.log("Value Received :" + el);
31 },
32 err => {
33 console.log("Error caught at Subscriber :" + err);
34 },
35 () => console.log("Processing Complete.")
36 );
37 }
38 }
39
40
41 ****Console ********
42 Value Received :2
43 Value Received :4
44 Error in the observable
45 Value Received :[object Object]
46 Value Received :8
47 Processing Complete
48
49
Source Code
The observable emits values 2 & 4.
When the map operator receive the value A it returns throwError. Remember throwError returns an observable. It
will raise the error notification, only if you subscribe to it.
The map operator does not subscribe to the observable. It just returns it to the subscriber.
Hence the subscriber receives the throwError observable as value. Hence you see [object Object] in the console.
Since there is no error raised, the observable continues and emits the next value 8 and then completes.
Using ThrowError
The throwError needs to be subscribed for it to emit error notification. We can use it to compose with other
Observables such as mergeMap, switchMap, catchError etc.
Using with catchError
The following example, shows how to use ThrowError with CatchError
1
2 import { Component, OnInit } from "@angular/core";
3 import { throwError, from } from "rxjs";
4 import { map, catchError } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12 srcArray = from([1, 2, "A", 4]);
13
14 obs = this.srcArray.pipe(
15 map(val => {
16 let result = (val as number) * 2;
17 if (Number.isNaN(result)) {
18 console.log("Errors Occurred in Stream");
19 throw new Error("Result is NaN");
20 }
21 return result;
22 }),
23 catchError(error => {
24 console.log("Caught in CatchError. Throwing error");
25 return throwError(error);
26 })
27 );
28
29 ngOnInit() {
30 this.obs.subscribe(
31 el => {
32 console.log("Value Received " + el);
33 },
34 err => {
35 console.log("Error caught at Subscriber " + err);
36 },
37 () => console.log("Processing Complete.")
38 );
39 }
40 }
41
42
43 ******* CONSOLE *******
44 Value Received 2
45 Value Received 4
46 Errors Occurred in Stream
47 Caught in CatchError. Throwing error
48 Error caught at Subscriber Error: Result is NaN
49
50
Source Code
The code throws the error using throw error in map operator.
CatchError will catch this error. We use the CatchError to handle the errors thrown by the Angular Observable. Once
we handle the error, we must return an observable. We can either return a replacement observable or return an
error. The observable returned from CatchError is immediately subscribed.
Hence we can use the throwError here, which is immediately subscribed , which in turn emits an error notification
1
2 catchError(error => {
3 console.log("Caught in CatchError. Throwing error");
4 return throwError(error);
5 })
6
7
Using it with MergeMap
The Angular MergeMap maps each value from the source observable into an inner observable, subscribes to it, and
then starts emitting the values from it.
In the following example, we use throwError to return a observable, when we receive the value 3.
The MergeMap subscribes to this new observable and raises the error notification and stops.
1
2 import { Component, OnInit } from "@angular/core";
3 import { throwError, of } from "rxjs";
4 import { map, mergeMap, catchError } from "rxjs/operators";
5
6 @Component({
7 selector: "my-app",
8 templateUrl: "./app.component.html",
9 styleUrls: ["./app.component.css"]
10 })
11 export class AppComponent {
12 srcObservable = of(1, 2, 3, 4);
13 innerObservable = of("A", "B");
14
15 obs = this.srcObservable.pipe(
16 mergeMap(val => {
17 console.log("Source value " + val);
18 console.log("starting new observable");
19
20 if (val == 3) return throwError("Error in observable");
21
22
23 return this.innerObservable;
24 })
25 );
26
27 ngOnInit() {
28 this.obs.subscribe(
29 el => {
30 console.log("Value Received " + el);
31 },
32 err => {
33 console.log("Error caught at Subscriber " + err);
34 },
35 () => console.log("Processing Complete.")
36 );
37 }
38 }
39
40
41 ***Console ****
42 Source value 1
43 starting new observable
44 Value Received A
45 Value Received B
46 Source value 2
47 starting new observable
48 Value Received A
49 Value Received B
50 Source value 3
51 starting new observable
52 Error caught at Subscriber Error in observable
53
Source Code
Using Catcherror Operator in Angular Observable
Leave a Comment / 6 minutes of reading / January 26, 2021
ThrowError
ReTry & ReTryWhen
Angular CatchError is an RxJs Operator. We can use it to handle the errors thrown by the Angular Observable. Like all
other RxJs operators, the CatchError also takes an observable as input and returns an observable (or throws an
error). We can use CatchError to provide a replacement observable or throw a user-defined error. Let us learn all
these in this tutorial.
Catch operator was renamed as catchError in RxJs 5.5, Hence if you are using Angular 5 or prior version then use
catch instead of catchError.
Table of Contents
Handling Errors in Observable
Using Error Callback of Subscribe method
Catch errors in the observable stream
Using CatchError Operator
Syntax
Returning a new observable
Throws a new Error
Retrying
References
Handling Errors in Observable
We can handle the errors at two places.
Using the error callback of the subscribe method
Catch errors in the observable stream
Using Error Callback of Subscribe method
We subscribe to an Observable by using the subscribe method. The subscribe method accepts three callback
methods as arguments. They are the next value, error, or complete event. We use the error callback to catch &
handle the errors.
For Example, consider the following code. The obs observable multiplies the values (srcArray) by 2 using
the map operator. If the result is NaN, then we throw an error using throw new Error("Result is NaN").
ReTry & ReTryWhen Operators help us to retry a failed observable in Angular. These operators are useful in Error
handling. They both resubscribe to the source observable when they receive onError() notification.
Table of Contents
ReTry
ReTry Example
ReTryWhen
How it works
ReTryWhen Example
Adding a Delay
Notifier observable
Limiting Retry Attempts
References
ReTry
The ReTry Angule RxJs operator retries a failed source observable count number of times. If the count is not
provided then it tries indefinitely
Syntax
1
2 retry<T>(count: number = -1): MonoTypeOperatorFunction<T>
3
Mirrors the source observable, if there are no errors.
If the source observable calls error notification, it does not propagate it. But re subscribes to the source again for a
maximum of count times.
The Retry operator retries the operation immediately
ReTry Example
In the example below, map operator throws an error if the source emits a value greater than 3.
The ReTry(2) retries the operation twice before erroring out.
1
2 import { Component } from "@angular/core";
3 import { map, retry, tap } from "rxjs/operators";
4 import { interval } from "rxjs";
5
6 @Component({
7 selector: "my-app",
8 template: `
9 <h1>Retry And ReTryWhen Example</h1>
10 `,
11 styleUrls: ["./app.component.css"]
12 })
13 export class AppComponent {
14 ngOnInit() {
15 interval(1000)
16 .pipe(
17 map(val => {
18 if (val > 2) throw new Error("Invalid Value");
19 return val;
20 }),
21 retry(2)
22 )
23 .subscribe(
24 val => console.log(val),
25 err => console.log(err),
26 () => console.log("Complete")
27 );
28 }
29 }
30
31
Source Code
Retry without any argument, will retry indefinitely
1
2 interval(1000)
3 .pipe(
4 map(val => {
5 if (val > 2) throw new Error("Invalid Value");
6 return val;
7 }),
8 retry()
9 )
10 .subscribe(val => console.log(val));
11
Retry(0) never retries.
1
2 interval(1000)
3 .pipe(
4 map(val => {
5 if (val > 2) throw new Error("Invalid Value");
6 return val;
7 }),
8 retry(0)
9 )
10 .subscribe(val => console.log(val));
11
ReTryWhen
The RetryWhen Angule RxJs operator retries the failed Observable every time a Notification Observable emits
the next value.
Syntax
1
2 retryWhen<T>(notifier: (errors: Observable<any>) => Observable<any>): MonoTypeOperatorFunction<T>
3
Where notifier is the callback, which returns the Notification Observable
How it works
We register the notifier callback with the ReTryWhen Operator.
The notifier gets the errors observable as the argument, which emits whenever the source observable errors
We return the notifier observable, which we build using the errors observable.
The ReTryWhen subscribes to this notifier observable and how it behaves depends on the value emitted by
the notifier observable
If the notifier emits a value, then ReTryWhen re subscribes the source observable.
In case of notifier emitting an error, then ReTryWhen also emits an error.
If the notifier completes, then ReTryWhen does nothing.
ReTryWhen Example
In the following example, map operator throws an error if the val > 2.
The errors are caught by retryWhen. It gets the error observable as its input. We use the pipe operator to add
a tap to print the Retrying message on the console.
This code runs indefinitely as the source will always errors out and there is nothing to stop retryWhen
1
2 import { Component } from "@angular/core";
3 import { map, retryWhen, tap, take } from "rxjs/operators";
4 import { interval, Observable, observable, of, throwError, timer } from "rxjs";
5
6 @Component({
7 selector: "my-app",
8 template: `
9 <h1>Retry And ReTryWhen Example</h1>
10 `,
11 styleUrls: ["./app.component.css"]
12 })
13 export class AppComponent {
14 ngOnInit() {
15 interval(1000)
16 .pipe(
17 map(val => {
18 if (val > 2) throw new Error("Invalid Value");
19 return val;
20 }),
21 retryWhen(
22 error => error.pipe(
23 tap(() => console.log("Retrying... "))))
24 )
25 .subscribe(
26 val => console.log(val),
27 err => console.log(err),
28 () => console.log("Complete")
29 );
30 }
31 }
32
33 **Console **
34
35
36 0
37 1
38 2
39 Retrying..
40 0
41 1
42 2
43 Retrying..
44
Source Code
Returning the error observable as it is also retries the source indefinitely
1
2 interval(1000)
3 .pipe(
4 map(val => {
5 if (val > 2) throw new Error("Invalid Value");
6 return val;
7 }),
8 retryWhen(error => error)
9 )
10 .subscribe(
11 val => console.log(val),
12 err => console.log(err),
13 () => console.log("Complete")
14 );
15
Source Code
Adding a Delay
The following code adds delay of 2000 ms.
1
2 interval(1000)
3 .pipe(
4 map(val => {
5 if (val > 2) throw new Error("Invalid Value");
6 return val;
7 }),
8 retryWhen(
9 error =>
10 error.pipe(
11 tap(() => console.log("error occurred ")),
12 delay(2000),
13 tap(() => console.log("Retrying ..."))
14 )
15 )
16 )
17 .subscribe(
18 val => console.log(val),
19 err => console.log(err),
20 () => console.log("Complete")
21 );
22
Source Code
Notifier observable
As long as the notifier observable emits a value, the retryWhen will re subscribes to the source again.
In the following example, we switch observable to a new observable using SwitchMap operator. The new observable
(of Operator) emits the value 1 after a delay of 1000 ms and the source is resubscribed again.
1
2 interval(1000)
3 .pipe(
4 map(val => {
5 if (val > 2) throw new Error("Invalid Value");
6 return val;
7 }),
8 retryWhen(error =>
9 error.pipe(
10 switchMap(() =>
11 of(1).pipe(
12 delay(1000),
13 tap(() => console.log("of emitted"))
14 )
15 ),
16 tap(() => console.log("Retrying ..."))
17 )
18 )
19 )
20 .subscribe(
21 val => console.log(val),
22 err => console.log(err),
23 () => console.log("Complete")
24 );
25
Source Code
The following uses of() instead of(1). of() does not emit any values but sends a complete notification on subscription.
In this case, RetryWhen does not retry the source but completes. The subscribers will not receive any notification.
1
2 interval(1000)
3 .pipe(
4 map(val => {
5 if (val > 2) throw new Error("Error: Value greater than 2");
6 return val;
7 }),
8 retryWhen(error =>
9 error.pipe(
10 switchMap(() =>
11 of().pipe(
12 delay(1000),
13 tap(() => console.log("of emitted"))
14 )
15 ),
16 tap(() => console.log("Retrying ..."))
17 )
18 )
19 )
20 .subscribe(
21 val => console.log(val),
22 err => console.error(err),
23 () => console.log("Complete")
24 );
25
Source Code
Here is another interesting example where we switch to interval(3000) observable.
When the error occurs the first time in the source, RetryWhen triggers the interval(3000). When it emits a value
source is re-subscribed.
But, the interval(3000) is going to emit another value after 3000ms. In this case, the RetryWhen will re subscribes to
the source again, even if the source has errored out or already completed.
1
2 interval(1000)
3 .pipe(
4 map(val => {
5 if (val > 2) throw Error;
6 return val;
7 }),
8 retryWhen(error =>
9 error.pipe(
10 tap(() => console.log("error tapped")),
11 switchMap(() =>
12 interval(3000).pipe(tap(() => console.log("interval")))
13 ),
14 tap(() => console.log("Retrying ..."))
15 )
16 )
17 )
18 .subscribe(
19 val => console.log(val),
20 err => console.log(err),
21 () => console.log("Complete")
22 );
23
24 *** Console ***
25 0
26 1
27 2
28 error tapped
29 interval
30 Retrying ...
31 0
32 1
33 interval
34 Retrying ...
35 0
36 1
37 interval
38 Retrying ...
39
40
Source Code
Limiting Retry Attempts
In the example below, we use the scan operator to count the number of tries and throw an error if the number of
attempts exceeds 2.
1
2 interval(1000)
3 .pipe(
4 map(val => {
5 if (val > 2) throw new Error("Invalid Value");
6 return val;
7 }),
8 retryWhen(error =>
9 error.pipe(
10 scan((acc, error) => {
11 if (acc > 2) throw error;
12 console.log("attempt " + acc);
13 return acc + 1;
14 }, 1),
15 delay(3000),
16 tap(() => console.log("Retrying ..."))
17 )
18 )
19 )
20 .subscribe(
21 val => console.log(val),
22 err => console.error(err),
23 () => console.log("Complete")
24 );
25
26
27 *** Console ***
28 0
29 1
30 2
31 attempt 1
32 Retrying ...
33 0
34 1
35 2
36 attempt 2
37 Retrying ...
38 0
39 1
40 2
41 Invalid Value
42
43
Source Code
Use the dealyWhen to increase the time duration between each retries.
1
2 interval(1000)
3 .pipe(
4 map(val => {
5 if (val > 2) throw new Error("Invalid Value");
6 return val;
7 }),
8 retryWhen(error =>
9 error.pipe(
10 scan((acc, error) => {
11 if (acc > 2) throw error;
12 console.log("attempt " + acc);
13 return acc + 1;
14 }, 1),
15 delayWhen(val => timer(val * 2000)),
16 tap(() => console.log("Retrying ..."))
17 )
18 )
19 )
20 .subscribe(
21 val => console.log(val),
22 err => console.error(err),
23 () => console.log("Complete")
24 );
25
Source Code
You can also use the take or takeWhile operator to stop the retries and emit the complete notification.
1
2 interval(1000)
3 .pipe(
4 map(val => {
5 if (val > 2) throw new Error("Invalid Value");
6 return val;
7 }),
8 retryWhen(error =>
9 error.pipe(
10 scan((acc, error) => {
11 console.log("attempt " + acc);
12 return acc + 1;
13 }, 1),
14 take(2),
15 delayWhen(val => timer(val * 2000)),
16 tap(() => console.log("Retrying ..."))
17 )
18 )
19 )
20 .subscribe(
21 val => console.log(val),
22 err => console.error(err),
23 () => console.log("Complete")
24 );
25 }
26
Unsubscribing from an Observable in Angular
1 Comment / 6 minutes of reading / May 16, 2021
ReTry & ReTryWhen
Subjects in Angular
In this tutorial let us learn how to Unsubscribe from an observable in angular. An observable which is not
Unsubscribed will lead to memory leak & Performance degradation.
Table of Contents
Why Unsubscribe
How to Unsubscribe
When to Unsubscribe
Various ways to Unsubscribe
Use Async Pipe
Using Take or First Operator
Use Unsubscribe
Using Array to store subscription
Using TakeUntil
Using TakeUntil in a base component
Reference
Why Unsubscribe
In the example below, we have ChildComponent, which subscribes to an observable in its ngOnInit hook. The
observable emits a new value for every 2000 ms.
In the AppComponent, we use the ngIf to show and remove the ChildComponent.
app.component.html
1
2 <h1>Angular Unsubscribe from Observable Example</h1>
3
4 Show Child :
5 <input
6 type="checkbox"
7 id="showChild"
8 name="showChild"
9 import { Component, VERSION } from "@angular/core";
10
11 @Component({
12 selector: "my-app",
13 template: `
14 <h1>Angular Unsubscribe from Observable Example</h1>
15
16 Show Child :
17 <input
18 type="checkbox"
19 id="showChild"
20 name="showChild"
21 [(ngModel)]="showChild"
22 />
23
24 <app-child-component *ngIf="showChild"></app-child-component>
25 `,
26 styleUrls: ["./app.component.css"]
27 })
28 export class AppComponent {
29 name = "Angular " + VERSION.major;
30
31 showChild = false;
32 }
33
34
Child.Component.ts
1
2 import { Component, OnInit } from "@angular/core";
3 import { timer, interval } from "rxjs";
4
5 @Component({
6 selector: "app-child-component",
7 templateUrl: "./child.component.html",
8 styleUrls: ["./child.component.css"]
9 })
10 export class ChildComponent implements OnInit {
11 src = interval(2000);
12 id = Date.now();
13
14 constructor() {}
15
16 ngOnInit() {
17 console.log("Component Created " + this.id);
18
19 this.src.subscribe(value => {
20 console.log("Received " + this.id);
21 });
22 }
23
24 ngOnDestroy() {
25 console.log("Component Destroyed " + this.id);
26 }
27 }
28
29
Source Code
The subscription starts to emit values when the child component is rendered by Angular. But when we destroy the
component, the observable still keeps emitting new values. We can see this in console window.
If we render the child component again, it starts a new subscription. Now we have two subscriptions running. As and
when we create a new instance of the child component, it will create a new subscription, and those subscriptions
never cleaned up.
How to Unsubscribe
Unsubscribing from an observable as easy as calling Unsubscribe() method on the subscription. It will clean up all
listeners and frees up the memory
To do that, first create a variable to store the subscription
1
2 obs: Subscription;
3
Assign the subscription to the obs variable
1
2 this.obs = this.src.subscribe(value => {
3 console.log("Received " + this.id);
4 });
5
6
Call the unsubscribe() method in the ngOnDestroy method.
1
2 ngOnDestroy() {
3 this.obs.unsubscribe();
4 }
5
6
When we destroy the component, the observable is unsubscribed and cleaned up.
The final code is shown below
Child.Component.ts
1
2 import { Component, OnInit } from "@angular/core";
3 import { timer, interval, Subscription } from "rxjs";
4
5 @Component({
6 selector: "app-child-component",
7 templateUrl: "./child.component.html",
8 styleUrls: ["./child.component.css"]
9 })
10 export class ChildComponent implements OnInit {
11 src = interval(2000);
12 id = Date.now();
13 obs: Subscription;
14
15 constructor() {}
16
17 ngOnInit() {
18 console.log("Component Created " + this.id);
19
20 this.obs = this.src.subscribe(value => {
21 console.log("Received " + this.id);
22 });
23 }
24
25 ngOnDestroy() {
26 console.log("Component Destroyed " + this.id);
27 this.obs.unsubscribe();
28 }
29 }
30
31
Source Code
When to Unsubscribe
There is no need to unsubscribe from every subscription. For Example, the observables, which are finite in nature.
Although it does not harm if you do so.
In Angular you do not have to Unsubscribe in the following scenarios
The HttpClient Observables like HTTP get & post, etc. They Complete after returning only one value.
The Angular Router also emits several observables like paramMap, queryParamMap, fragment, data, URL, Events,
etc. The Router Modules take care of unsubscribing.
All finite observables.
You need to Unsubscribe in the following scenarios
Any Observable that you create in your Angular component or Angular services.
ValueChanges & StatusChanges observables from Angular Forms
The listens to the DOM events from the Renderer2 service
All infinite observables.
When in doubt, always Unsubscribe
Various ways to Unsubscribe
Use Async Pipe
Use Async pipe to subscribe to an observable, it automatically cleans up, when we destroy the component.
Using Take or First Operator
Convert all infinite observables to finite observable using the Take or First Operators.
The Take Operator emits the first n number of values and then stops the source observable.
1
2 export class AppComponent {
3
4 obs = of(1, 2, 3, 4, 5).pipe(take(2));
5
6 ngOnInit() {
7 this.obs.subscribe(val => console.log(val));
8 }
9 }
10
11 ****Console ******
12 1
13 2
14
The first operator emits the first value and then stops the observable. But It sends an error notification if does not
receive any value.
1
2 export class AppComponent {
3
4 obs = of(1, 2, 3, 4, 5).pipe(first());
5
6 ngOnInit() {
7 this.obs.subscribe(val => console.log(val));
8 }
9 }
10
11 ****Console ******
12 1
13
14
Use Unsubscribe
Using Unsubscribe is the simplest & easiest way.
Store each subscription in a local variable and call unsubscribe on them in the ngOnDestroy hook
1
2 import { Component, OnInit } from "@angular/core";
3 import { timer, interval, Subscription } from "rxjs";
4
5 @Component({
6 selector: "app-child-component",
7 templateUrl: "./child.component.html",
8 styleUrls: ["./child.component.css"]
9 })
10 export class ChildComponent implements OnInit {
11 src1 = interval(1000);
12 src2 = interval(1500);
13 src3 = interval(2000);
14
15 id = Date.now();
16 obs1: Subscription;
17 obs2: Subscription;
18 obs3: Subscription;
19
20 constructor() {}
21
22 ngOnInit() {
23 console.log("Component Created " + this.id);
24
25 this.obs1 = this.src1.subscribe(value => {
26 console.log("Src1 " + this.id);
27 });
28
29 this.obs2 = this.src2.subscribe(value => {
30 console.log("Src2 " + this.id);
31 });
32
33 this.obs3 = this.src3.subscribe(value => {
34 console.log("Src3 " + this.id);
35 });
36 }
37
38 ngOnDestroy() {
39
40 if (this.obs1) this.obs1.unsubscribe();
41 if (this.obs2) this.obs2.unsubscribe();
42 if (this.obs3) this.obs3.unsubscribe();
43
44 console.log("Component Destroyed " + this.id);
45 }
46 }
47
48
Source Code
Using Array to store subscription
Instead of local variable for each subscription, you can create an array and add each subscription into it
1
2 let subs: Subscription[] = [];
3
Push each subscriptions to array
1
2 this.subs.push(
3 this.src1.subscribe(value => {
4 console.log("Src1 " + this.id);
5 })
6 );
7
In the ngOnDestroy hook, call unsubscribe on each subscriptions
1
2 ngOnDestroy() {
3 this.subs.forEach(sub => sub.unsubscribe());
4
5 console.log("Component Destroyed " + this.id);
6 }
7
Source Code
Using TakeUntil
We can make use of TakeUntil Operator.
The takeUntil operator emits values from the source observable until the notifier Observable emits a value. It then
completes the source observable.
To use takeUntil first, we create a notifier observable stop$
1
2 stop$ = new Subject<void>();
3
4
This notifier observable emits a value when the component is destroyed. We do that in ngOnDestroy hook.
1
2 ngOnDestroy() {
3 this.stop$.next();
4 this.stop$.complete();
5 }
6
7
We add the takeUntil(this.stop$) to all the observable we subscribe. When the component is destroyed all of them
automatically unsubscribed. Remember to add it to the last in the pipe Operator.
1
2 this.src.pipe(takeUntil(this.stop$)).subscribe(value => {
3 console.log("Obs1 " + this.id);
4 });
5
6
Complete code.
1
2 import { Component, OnInit } from "@angular/core";
3 import { timer, interval, Subscription, Subject } from "rxjs";
4 import { takeUntil } from "rxjs/operators";
5
6 @Component({
7 selector: "app-child-component",
8 templateUrl: "./child.component.html",
9 styleUrls: ["./child.component.css"]
10 })
11 export class ChildComponent implements OnInit {
12 stop$ = new Subject<void>();
13 src = interval(2000);
14
15 id = Date.now();
16
17 constructor() {}
18
19 ngOnInit() {
20 console.log("Component Created " + this.id);
21
22 this.src.pipe(takeUntil(this.stop$)).subscribe(value => {
23 console.log("Obs1 " + this.id);
24 });
25
26 this.src.pipe(takeUntil(this.stop$)).subscribe(value => {
27 console.log("Obs2 " + this.id);
28 });
29 }
30
31 ngOnDestroy() {
32 this.stop$.next();
33 this.stop$.complete();
34 console.log("Component Destroyed " + this.id);
35 }
36 }
37
Source Code
Using TakeUntil in a base component
Instead of creating the notifier observable in every component, you can create on in a BaseComponent and reuse it
everywhere.
base.component.ts
1
2 import { Component, OnDestroy } from "@angular/core";
3 import { Subject } from "rxjs";
4
5 @Component({
6 template: ``
7 })
8 export class BaseComponent implements OnDestroy {
9 stop$ = new Subject<void>();
10
11 ngOnDestroy() {
12 this.stop$.next();
13 this.stop$.complete();
14 console.log("BaseComponent Destroyed ");
15 }
16 }
17
18
Extend every component using BaseComponent.
child.component.ts
1
2 import { Component, OnInit } from "@angular/core";
3 import { timer, interval, Subscription, Subject } from "rxjs";
4 import { takeUntil } from "rxjs/operators";
5 import { BaseComponent } from "../base.component";
6
7 @Component({
8 selector: "app-child-component",
9 templateUrl: "./child.component.html",
10 styleUrls: ["./child.component.css"]
11 })
12 export class ChildComponent extends BaseComponent implements OnInit {
13 src = interval(2000);
14
15 id = Date.now();
16
17 constructor() {
18 super();
19 }
20
21 ngOnInit() {
22 console.log("Component Created " + this.id);
23
24 this.src.pipe(takeUntil(this.stop$)).subscribe(value => {
25 console.log("Obs1 " + this.id);
26 });
27
28 this.src.pipe(takeUntil(this.stop$)).subscribe(value => {
29 console.log("Obs2 " + this.id);
30 });
31 }
32
33 ngOnDestroy() {
34 super.ngOnDestroy();
35 console.log("Component Destroyed " + this.id);
36 }
37 }
38
39
Source Code
Note that if you wish you use the constructor or ngOnDestroy in the child component, then remember to use
the super & super.ngOnDestroy() to call the base constructor & ngOnDestroy of the base component.
Parent to Child: Sharing Data via Input
This is probably the most common and straightforward method of sharing data. It works by using
the @Input() decorator to allow data to be passed via the template.
parent.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
template: `
<app-child [childMessage]="parentMessage"></app-child>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent{
parentMessage = "message from parent"
constructor() { }
}
child.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: `
Say {{ message }}
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
constructor() { }
}
Child to Parent: Sharing Data via ViewChild
ViewChild allows a one component to be injected into another, giving the parent access to its attributes and
functions. One caveat, however, is that child won’t be available until after the view has been initialized. This means
we need to implement the AfterViewInit lifecycle hook to receive the data from the child.
parent.component.ts
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from "../child/child.component";
@Component({
selector: 'app-parent',
template: `
Message: {{ message }}
<app-child></app-child>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements AfterViewInit {
@ViewChild(ChildComponent) child;
constructor() { }
message:string;
ngAfterViewInit() {
this.message = this.child.message
}
}
child.component.ts
import { Component} from '@angular/core';
@Component({
selector: 'app-child',
template: `
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
constructor() { }
}
Child to Parent: Sharing Data via Output() and EventEmitter
Another way to share data is to emit data from the child, which can be listened to by the parent. This approach is
ideal when you want to share data changes that occur on things like button clicks, form entires, and other user
events.
In the parent, we create a function to receive the message and set it equal to the message variable.
In the child, we declare a messageEvent variable with the Output decorator and set it equal to a new event emitter.
Then we create a function named sendMessage that calls emit on this event with the message we want to send.
Lastly, we create a button to trigger this function.
The parent can now subscribe to this messageEvent that’s outputted by the child component, then run the receive
message function whenever this event occurs.
parent.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
template: `
Message: {{message}}
<app-child (messageEvent)="receiveMessage($event)"></app-child>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
constructor() { }
message:string;
receiveMessage($event) {
this.message = $event
}
}
child.component.ts
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
template: `
<button (click)="sendMessage()">Send Message</button>
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
constructor() { }
sendMessage() {
this.messageEvent.emit(this.message)
}
}
Unrelated Components: Sharing Data with a Service
When passing data between components that lack a direct connection, such as siblings, grandchildren, etc, you
should have a shared service. When you have data that should aways been in sync, I find the RxJS
BehaviorSubject very useful in this situation.
You can also use a regular RxJS Subject for sharing data via the service, but here’s why I prefer a BehaviorSubject.
It will always return the current value on subscription - there is no need to call onnext
It has a getValue() function to extract the last value as raw data.
It ensures that the component always receives the most recent data.
In the service, we create a private BehaviorSubject that will hold the current value of the message. We define a
currentMessage variable handle this data stream as an observable that will be used by the components. Lastly, we
create function that calls next on the BehaviorSubject to change its value.
The parent, child, and sibling components all receive the same treatment. We inject the DataService in the
constructor, then subscribe to the currentMessage observable and set its value equal to the message variable.
Now if we create a function in any one of these components that changes the value of the message. when this
function is executed the new data it’s automatically broadcast to all other components.
data.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable()
export class DataService {
constructor() { }
changeMessage(message: string) {
this.messageSource.next(message)
}
}
parent.component.ts
import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";
import { Subscription } from 'rxjs';
@Component({
selector: 'app-parent',
template: `
{{message}}
`,
styleUrls: ['./sibling.component.css']
})
export class ParentComponent implements OnInit, OnDestroy {
message:string;
subscription: Subscription;
ngOnInit() {
this.subscription = this.data.currentMessage.subscribe(message => this.message = message)
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
sibling.component.ts
import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";
import { Subscription } from 'rxjs';
@Component({
selector: 'app-sibling',
template: `
{{message}}
<button (click)="newMessage()">New Message</button>
`,
styleUrls: ['./sibling.component.css']
})
export class SiblingComponent implements OnInit, OnDestroy {
message:string;
subscription: Subscription;
ngOnInit() {
this.subscription = this.data.currentMessage.subscribe(message => this.message = message)
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
newMessage() {
this.data.changeMessage("Hello from Sibling")
}
}
Introduction
Directives are a very important feature provided by Angular. Even Angular Components are actually higher-order
directives with their own template.
In this guide, we'll look into the various types of directives and then learn how to build one for our application's
custom requirements.
Types of Directives
Angular has two main types of directives:
Attribute
Structural
Attribute Directives
Attribute directives get applied to the element's attributes. Thus, they are useful to manipulate our DOM by
updating certain attributes but do not create or destroy element's as such. Thus, they can also be referred to as
DOM-friendly directives. They only change the DOM element they are attached to. They mostly use data binding or
event binding.
They can be useful in the following scenarios:
Applying styles or classes to certain elements conditionally
Example below:
1<div [style.color]="'green'">Very excited to learn about building Custom Directives !!</div>
html
Showing or hiding elements conditionally
Example below:
1<div [hidden]="showHideEl">Very excited to learn about building Custom Directives !!</div>
html
Changing the behavior of any component dynamically, depending on any property
Structural Directives
Structural directives, on the other hand, can create, delete, or re-create DOM elements based on certain inputs.
Thus, they are generally not DOM-friendly.
Let's talk about what the "hidden" attribute directive does. It retains the element in the DOM, but only hides it from
the user, while structural directives such as *ngIf remove the element from the DOM.
The other commonly used structural directives are ngFor and ngSwitch which can be used for routing programming
tasks.
Custom Directive
There are many use cases in our app, where we have a custom requirement and have to create a custom directive as
per our requirement. This is where we'll need to create a custom directive.
Angular has some basic APIs which can help us create custom directives. Let us first have a look at creating a custom
attribute directive.
Custom Attribute Directives
Say we have a requirement where we want any element to be styled in a particular way (e.g. with a background
highlight color and some text/foreground color). We can have such a text in multiple places, so we can create a
custom directive for the same and reuse it across our application. So essentially, we want to be able to use our
directive as below:
1<div class="para float-left" myHighlight>Some text to be highlighted !</div>
html
To create the directive, we can run the following command using the Angular CLI:
1ng generate directive myHighlight
The above command would automatically update the entry in our app.module.ts. However, if we create the directive
manually, we'll need to update this in our AppModule as below:
1import { NgModule } from '@angular/core';
2import { BrowserModule } from '@angular/platform-browser';
3import { AppComponent } from './app.component';
4
5import { MyHighlightDirective } from './myhighlight.directive';
6
7@NgModule({
8 imports: [ BrowserModule ],
9 declarations: [
10 AppComponent,
11 MyHighlightDirective
12 ],
13 bootstrap: [ AppComponent ]
14})
15export class AppModule { }
javascript
The above would inform Angular about our new directive and this is how it knows which class to invoke whenever it
encounters the selector in the template.
We'll now start with the decorator. So, any directive class has to be annotated by using a @Directive decorator.
Let us create a class called "MyHighlightDirective" and then use the @Directive decorator to associate our class with
the attribute "myHighlight", as shown below:
1import { Directive } from '@angular/core';
2//...
3//...
4//...
5@Directive({
6 selector:"[myHighlight]"
7})
8export class MyHighlightDirective { }
javascript
As you can see, we marked the class using the @Directive decorator and have to import the same from
@angular/core.
Also, the code shown above is quite similar to how we write a component. One of the differences we can see is that
our selector is wrapped inside []. This is because our selector attribute internally uses the same CSS matching rules to
match any directive or component and map it to any HTML element.
Thus, if we have to select any particular element via CSS, we just write the name of the element like say div
{background-color: 'green'}. And this is why, in the selector for the component in the @Component directive, we just
specify the name of the component.
If we update the selector in our directive as below:
1import { Directive } from '@angular/core';
2//...
3//...
4//...
5@Directive({
6 selector:".myHighlight"
7})
8export class MyHighlightDirective { }
javascript
With the above definition, our directive would be associated with any element which has a class "myHighlight"
defined like:
1<div class="para float-left myHighlight">Some text to be highlighted !</div>
html
For now, let us associate our directive to an element with the attribute "myHighlight".
Once we have our decorator added, the next step would be to add a constructor to our directive, as shown below:
1import { Directive } from '@angular/core';
2import { ElementRef } from '@angular/core';
3//...
4//...
5//...
6@Directive({
7 selector:"[myHighlight]"
8})
9export class MyHighlightDirective {
10 constructor(private elRef: ElementRef) {}
11}
javascript
With the above code, we are telling Angular to inject an instance of ElementRef into its constructor, whenever the
directive is created. This is actually via dependency injection.
ElementRef is used to get direct access to the DOM element on which our directive attribute is attached to.
Let's say we now want to change the background color of this element to green and the foreground color to blue. To
do that, we'll write the following code:
1el.nativeElement.style.backgroundColor = "green";
2el.nativeElement.style.color = "blue";
javascript
ElementRef is actually a wrapper for our actual DOM element and we access the DOM element using the property
nativeElement on it.
We'll write the above code inside our ngOnInit method. So this is how our directive class would now look like;
1import { Directive } from '@angular/core';
2import { ElementRef } from '@angular/core';
3//...
4//...
5//...
6@Directive({
7 selector:"[myHighlight]"
8})
9export class MyHighlightDirective {
10 constructor(private elRef: ElementRef) {}
11 ngOnInit() {
12 this.elRef.nativeElement.style.backgroundColor = "green";
13 this.elRef.nativeElement.style.color = "blue";
14 }
15}
javascript
The only issue with the above style of using directives is that this would assume that our app would always run in a
browser. However, that might not be the case always. We can have our app running in a different environment like
on a native mobile device. Thus, Angular has provided with an API which is platform independent and we can set
properties on our elements using Renderer.
This is how our class would get updated to if we use the Renderer helper:
1import { Directive } from '@angular/core';
2import { Renderer } from '@angular/core';
3//...
4//...
5//...
6@Directive({
7 selector:"[myHighlight]"
8})
9export class MyHighlightDirective {
10 constructor(private elRef: ElementRef, private renderer: Renderer) {}
11 ngOnInit() {
12 this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'green');
13 this.renderer.setStyle(this.elRef.nativeElement, 'color', 'blue');
14 }
15}
javascript
The "setStyle" method has the following signature:
1setStyle(element: any, style: string, value: any, flags?: RendererStyleFlags2): void
javascript
Thus, we are now updating our DOM element's style (background and foreground color) via the "Renderer" and not
directly accessing our element, which is a good practice.
We are now applying a hardcoded background and foreground colors to the DOM element. Let's say that we want
that to be configurable, meaning our DOM element can say that it needs the background color and foreground color
to be something specific. Thus, we want to be able to say:
1<div class="para float-left" myHighlight [backgroundColor]="'black'" [foregroundColor]="'white'">Some text to be
highlighted !</div>
html
The above can be achieved with the help of @Input decorator. We'll also use the @HostBinding decorator to update
the styles on our element. Let us update our class showing the use of @Input and @HostBinding:
1import { Directive } from '@angular/core';
2import { Input } from '@angular/core';
3import { HostBinding } from '@angular/core';
4//...
5//...
6//...
7@Directive({
8 selector:"[myHighlight]"
9})
10export class MyHighlightDirective {
11 @Input() backgroundColor:string = 'green';
12 @Input() foregroundColor:string = 'blue';
13 @HostBinding('style.backgroundColor') bgColor:string;
14 @HostBinding('style.color') color:string;
15 constructor() {}
16 ngOnInit() {
17 this.bgColor = this.backgroundColor;
18 this.color = this.foregroundColor;
19 }
20}
javascript
If you see the above code, we now have default values for the background and foreground colors (i.e. green and
blue). However, if the values are passed to the directive via data binding, we instead use those values to set the
styles on our element.
We can also attach event listeners to our directive. Say, we want our text to have a different background and
foreground colors when the user hovers over it. Thus, we want to be able to pass this to our directive:
1<div class="para float-left" myHighlight
2 [backgroundColor]="'black'"
3 [foregroundColor]="'white'"
4 [hoverBackgroundColor]="'yellow'"
5 [hoverForegroundColor]="'red'">Some text to be highlighted !</div>
html
To be able to do this, we'll need to use the @HostListener decorator as shown below:
1import { Directive } from '@angular/core';
2import { Input } from '@angular/core';
3import { HostBinding } from '@angular/core';
4import { HostListener } from '@angular/core';
5//...
6//...
7//...
8@Directive({
9 selector:"[myHighlight]"
10})
11export class MyHighlightDirective {
12 @Input() backgroundColor:string = 'green';
13 @Input() foregroundColor:string = 'blue';
14 @Input() hoverBackgroundColor:string = 'gray';
15 @Input() hoverForegroundColor:string = 'orange';
16 @HostBinding('style.backgroundColor') bgColor:string;
17 @HostBinding('style.color') color:string;
18 constructor() {}
19 ngOnInit() {
20 this.bgColor = this.backgroundColor;
21 this.color = this.foregroundColor;
22 }
23 @HostListener('mouseenter') onMouseEnter(eventData: Event) {
24 this.bgColor = this.hoverBackgroundColor;
25 this.color = this.hoverForegroundColor;
26 }
27}
javascript
Thus, host listeners are just event listeners that get attached to the DOM element which is hosting our directive.
Custom Structural Directive
Now that we have an understanding of the custom attribute directive, let us have a quick look at how we can create
a custom Structural Directive. We can try recreating the in-built ngIf directive. Let us call that as "myCustomIf". This
is how the class for that would look like:
1import { Directive} from '@angular/core';
2import { Input, TemplateRef, ViewContainerRef } from '@angular/core';
3
4@Directive({
5 selector: '[myCustomIf]'
6})
7export class myCustomIfDirective {
8 constructor(
9 private template: TemplateRef<any>,
10 private container: ViewContainerRef
11 ) { }
12
13 @Input() set myIf(shouldAddToDOM: boolean) {
14 if (shouldAddToDOM) {
15 // If the value is true, add template to the DOM
16 this.container.createEmbeddedView(this.template);
17 } else {
18 // Otherwise delete template from the DOM
19 this.container.clear();
20 }
21 }
22
23}
javascript
We can now use this directive anywhere in our app. To do that, we'll just write;
1<!-- /app/my.component.html -->
2<div *myCustomIf="false">
3 Inside if
4</div>
html
Conclusion
Thus, we can see that directives can be really useful to implement any sort of custom logic on our DOM element.
While a lot of common functionalities can be achieved with the help of inbuilt directives, it is not uncommon to have
custom requirements in any app and in such cases, we can always write our own custom directive to get the desired
result. Also, we can write both the types of directive i.e. Attribute directive and Structural directive.
by
Dhananjay Kumar
·
Jan. 01, 18 · Tutorial
Like (14)
Comment (1)
Save
Tweet
230.86K Views
Join the DZone community and get the full member experience.
JOIN FOR FREE
To understand @HostListener and @HostBinding, you should have basic knowledge about directives in Angular.
There are three types of directives in Angular:
Component
Attribute Directive
Structural Directive
The basic difference between a component and a directive is that a component has a template, whereas an attribute
or structural directive does not have a template. To understand these two concepts, let us start by creating a simple
custom attribute directive. The directive below changes the background color of the host element:
1
import { Directive, ElementRef, Renderer } from '@angular/core';
2
3
@Directive({
4
selector: '[appChbgcolor]'
5
})
6
export class ChangeBgColorDirective {
7
8
constructor(private el: ElementRef, private renderer: Renderer) {
9
this.ChangeBgColor('red');
10
}
11
12
ChangeBgColor(color: string) {
13
14
this.renderer.setElementStyle(this.el.nativeElement, 'color', color);
15
}
16
}
To create a custom attribute directive, you need to create a class and decorate it with @Directive. In the constructor
of the directive class, inject the objects ElementRef and Renderer. Instances of these two classes are needed to get
the reference of the host element and of the renderer.
You can use the above attribute directive on a component template as shown in the code block below:
1
<div appChbgcolor>
2
<h3>{{title}}</h3>
3
</div>
Here, the component class holding the host element is created as below:
1
import { Component } from '@angular/core';
2
3
@Component({
4
selector: 'app-root',
5
templateUrl: './app.component.html',
6
styleUrls: ['./app.component.css']
7
})
8
export class AppComponent {
9
title = 'Hey ng Developer ! ';
10
}
Right now, the appChbgcolor directive will change the color of the host element.
@HostListener() Decorator
In Angular, the @HostListener() function decorator allows you to handle events of the host element in the directive
class.
Let's take the following requirement: when you hover you mouse over the host element, only the color of the host
element should change. In addition, when the mouse is gone, the color of the host element should change to its
default color. To do this, you need to handle events raised on the host element in the directive class. In Angular, you
do this using @HostListener() .
To understand @HostListener() in a better way, consider another simple scenario: on the click of the host element,
you want to show an alert window. To do this in the directive class, add @HostListener() and pass the event 'click' to
it. Also, associate a function to raise an alert as shown in the listing below:
1
@HostListener('click') onClick() {
2
window.alert('Host Element Clicked');
3
}
In Angular, the @HostListener() function decorator makes it super easy to handle events raised in the host element
inside the directive class. Let's go back to our requirement that says you must change the color to red only when the
mouse is hovering, and when it's gone, the color of the host element should change to black. To do this, you need to
handle the mouseenter and mouseexit events of the host element in the directive class. To achieve this, modify
the appChbgcolor directive class as shown below:
1
import { Directive, ElementRef, Renderer, HostListener } from '@angular/core';
2
3
@Directive({
4
selector: '[appChbgcolor]'
5
})
6
export class ChangeBgColorDirective {
7
8
constructor(private el: ElementRef, private renderer: Renderer) {
9
// this.ChangeBgColor('red');
10
}
11
12
@HostListener('mouseover') onMouseOver() {
13
this.ChangeBgColor('red');
14
}
15
16
@HostListener('click') onClick() {
17
window.alert('Host Element Clicked');
18
}
19
@HostListener('mouseleave') onMouseLeave() {
20
this.ChangeBgColor('black');
21
}
22
23
ChangeBgColor(color: string) {
24
25
this.renderer.setElementStyle(this.el.nativeElement, 'color', color);
26
}
27
}
In the directive class, we are handling the mouseenter and mouseexit events. As you see, we are using
@HostListener() to handle these host element events and assigning a function to it.
So, let's use @HostListener() function decorator to handle events of the host element in the directive class.
@HostBinding() Decorator
In Angular, the @HostBinding() function decorator allows you to set the properties of the host element from the
directive class.
Let's say you want to change the style properties such as height, width, color, margin, border, etc., or any other
internal properties of the host element in the directive class. Here, you'd need to use the @HostBinding() decorator
function to access these properties on the host element and assign a value to it in directive class.
The @HostBinding() decorator takes one parameter, the name of the host element property which value we want to
assign in the directive.
In our example, our host element is an HTML div element. If you want to set border properties of the host element,
you can do that using @HostBinding() decorator as shown below:
1
@HostBinding('style.border') border: string;
2
3
@HostListener('mouseover') onMouseOver() {
4
this.border = '5px solid green';
5
}
Using this code, on a mouse hover, the host element border will be set to a green, solid 5-pixel width. Therefore,
using the @HostBinding decorator, you can set the properties of the host element in the directive class.
Angular @HostBinding() and @HostListener() Example
November 13, 2022
Angular custom directives can take inputs using @HostBinding and add event listeners to elements
using @HostListener.
This Angular post is compatible with Angular 4 upto latest versions, Angular 7, Angular 8, Angular 9, Angular 10,
Angular 11, Angular 12 and Angular 13
In this tutorial, we will create a custom directive example from scratch which will take user inputs from a directive
element and use them in event listeners.
Let’s create a new Directive in the Angular application to demonstrate an element Highlighter directive which will
include color input by a user and mouse events to highlight the background of a div.
@Directive({
selector: '[appHighlighter]'
})
export class HighlighterDirective {
constructor() { }
}
Copy
To use a directive we also need to import it in the app.module.ts file's declaration array but NG CLI command will
automatically add it as shown below:
// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
@NgModule({
declarations: [
AppComponent,
HighlighterDirective
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Add Directive Element
Now we will add a <p/> tag element with some random text in the component template HTML with two properties:
[appHighlighter] : This property will act as the Directive selector added to the element as well as take a color name
or Hexacode, which will be the background color changed on the mouseenter event.
[defaultColor] : This property takes the color which will be added by default to the element.
Finally, the element with our directive will look like this:
<p
[appHighlighter]="'red'"
[defaultColor]="'yellow'"
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
Update Directive with @HostBinding and @HostListener
Let's add @HostBinding and @HostListener decorators and check what actually they do in a directive?
What is @HostBinding in Angular?
The host is actually the element on which we have added the directive attribute selector. By using the @HostBinding
we can control the properties on the host element, on which we have applied the directive selector.
We will use this decorator to set the background color on the directive by controlling the style attribute from the
directive class itself.
@HostBinding('style.backgroundColor') backgroundColor: string;
Copy
What is @HostListener in Angular?
The @HostListener decorator enable event binding to the host element which we will use inside our directive class
to bind mouseenter and mouseleave event listeners.
@HostListener('mouseenter') mouseover(eventData: Event) {
...
}
@Directive({
selector: '[appHighlighter]'
})
export class HighlighterDirective {
constructor() { }
ngOnInit() {
this.backgroundColor = this.defaultColor;
}
Conclusion: Here we discussed how to control the element behavior by adding a custom directive using
@HostBinding and @HostListener interface
=======================================================================================