RxJS Observables, Subjects and BehaviorSubjects in Angular
In this tutorial, we shall see about Observable, Subject and BehaviorSubject in angular.
What is an Observable?
Observables
are the one that works like publisher and subscriber model. The observable will have an observer
to publish any value and those who have subscribed to the observable can be able to get the updated value.
Create an Observable in TimerService
Let's understand this with an example.Create a service using
ng g s timer
Modify the code of service as below
import { Injectable } from '@angular/core';
import { Observable} from 'rxjs';
@Injectable()
export class TimerService {
private timer = new Observable((observer) => {
setInterval(() => {
observer.next(new Date());
}, 1000);
});
constructor() {}
getTimer() {
return this.timer;
}
}
In the above code, we imported the Observable
from rxjs package. To create an observable we use the new
keyword.
When creating an Observable
it takes a callback function with observer
as parameter.
This observer
will act like a producer which has been set to produce the date
for every 1 second and emit it using next function.
The timer
observable is declared as private, so that it cannot be accessed directly. If the getTimer() function is called, it will return the timer
observable.
Use the Observable in TimerService in AppComponent
Now in app.component.ts
file we modify the code as below
import { Component, OnInit } from '@angular/core';
import { TimerService } from './services/timer.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit, OnDestroy {
timer: Date;
subscriberObject;
constructor(private timerService: TimerService) {
}
ngOnInit(): void {
this.subscriberObject = this.timerService.getTimer().subscribe((value: Date) => {
this.timer = value;
});
}
ngOnDestroy(): void {
this.subscriberObject.unsubscribe();
}
}
In app.component.html
modify the code as
<p>Time: {{timer}}</p>
In app.component.ts
we have implemented the OnInit()
and OnDestroy()
lifecycle.
In OnInit()
life cycle, we will subscribe to the getTimer() function of TimerService
which will return an observable. The observable is assigned to the subscriberObject
.
In the ngOnDestroy()
life cycle event we unsubscribed
the subscriterObject
using unsubscribe() function.Its always neccessary to unsubscribe
any observable that is subscribed.
Now the application will display the time every one second. Remember to check whether the TimerService
is registered with the app module.
What are Subject?
As per the definition provided by rxjs. An RxJS Subject is a special type of Observable that allows values to be multicasted to many Observers. While plain Observables are unicast (each subscribed Observer owns an independent execution of the Observable), Subjects are multicast.
Subjects
are by default, is an Observable
which contains the methods next()
, error()
and complete()
. The next()
function is used to emit the latest value.
Creating Subject in TimerService
Let's update our previous example that was created with observable in TimerService
to use Subject
instead.
import { Injectable } from '@angular/core';
import { Subject} from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class TimerService {
private timer = new Subject<Date>();
constructor() {
setInterval(() => {
this.timer.next(new Date());
}, 1000);
}
getTimer() {
return this.timer.asObservable();
}
}
In the above code, we create a Subject
of typeDate
and assign to timer
variable.
In the constructor
of the service we create setInterval
to feed the new date to the timer
Subject
using next()
function. The timer
Subject
can be obtained as observable by calling getTimer() function.
Leave the codes for app.component.ts and app.component.html to be same as done for observable's example.
Now you can see the same output returning the date and time as returned by the observable.
What are BehaviorSubject?
BehaviorSubject
is a type of observable that is similar to the Subject but there are few differences. Some of them are
- It gets the initial value during its declaration.
- It will always return a value even if no data has been feed.
- If we subscribe to it, it will immediately return the last emitted value immediately.
Creating BehaviorSubject in TimerService
Let's modify the same program to use BehaviorSubject
instead of Subject
.
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class TimerService {
private timer = new BehaviorSubject<Date>(new Date());
constructor() {
setInterval(() => {
this.timer.next(new Date());
}, 1000);
}
getTimer() {
return this.timer.asObservable();
}
}
Here, instead of importing Subject
we imported BehaviorSubject
. We create the BehaviorSubject
of type Date
with initial value of current date.
Leave the codes for app.component.ts and app.component.html to remain the same.
Now you can notice that when the app loads, it will load with the initial date and time. This behaviour is because the BehaviorSubject will immediately emit the date value.