RxJS Observable Demystify (2024)
RxJS Tutorial - Table of Contents
Overview
RxJS stands for JavaScript Reactive Extensions and its library that implements the ReactiveX API.
RxJS is awesome for reactive programming, making it easy to write asynchronous code with Observable
Observable has become an ES7 feature that is increasingly used, meaning you don't have to use an external library to use it. RxJS also offers Observable operators to manipulate your data.
Observable:
An Observable is just a function with a few special features, which uses an "observer" (an object with "next," "error" and "complete" methods) and returns an cancelation logic.
- This is a class representing a stream of data.
- The observable function is a function that produces a flow of values for an observer over time.
- Observable are cancelable, which gives better control when dealing with in-flow values from stream over promise
- You are an observer if you subscribe to an observable.
- An observable can have multiple observers.
The ability of observable to handle multiple values over time makes them a good candidate to work with real-time data, events, and any stream you might think of.
To work with observable, Lets understand the stream, the stream in the world of RxJS simply represents values (or events) over time, and the Observable are what facilitates the stream in Angular.
Lifecycle of Observable
The observable instance goes through all four phases of its lifespan with assistance from observers and subscriptions:
- Creation
- Subscription
- Execution
- Destruction
Let's see simple example of Observable
Below is basic example before we immerse ourselves in our real world example.
import { Observable } from "rxjs/Observable";
export class AppComponent implements OnInit OnDestroy{
const subscription;
ngOnInit(): void {
// Creating Observable
const observable$ = Observable.create((observer:any) => {
try {
//Execution
observer.next('First value')
observer.next('Second value')
setInterval(() => {
observer.next('Async value')
observer.complete();
observer.next('value not send')
}, 1000)
} catch (err) {
observer.error(err)
}
})
// Subscribing to Observable
this.subscription = observable$.subscribe(function logMessage(message:any) {
console.log(message);
})
}
ngOnDestroy() {
// Destruction
this.subscription.unsubscribe();
}
}
In this example, we first created the observable. The observer is in charge of executing instructions in the Observable, so each observer that subscribes can deliver three values to the Observable, which include:
- next
- error
- complete
In our above example, once we subscribe to observable we will start getting observable data, This will appear like below` in your browser console:
First value
Second value
Async value
Now Let’s see the simple use of RxJS in Angular
In the context of using RxJS for creating Angular applications, an Observable instance will be created by doing one of the following things:
- Creating or fetching data over HTTP with AJAX
- Listening to input changes with reactive fors
- Listening to routing changes
- Listening to UI events
- Wrapping an asynchronous concept
Creating HTTP requests is a critical part of the life of most front-end applications. Angular, which is the hottest thing right now, has a really cool way to do that. To make HTTP requests using the RxJS Observable Library.
Angular is incredible; with angular, you can manage HTTP requests using observable rather than promises.
When you look at the HTTP signature in the Angular source
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response>;
get(url: string, options?: RequestOptionsArgs): Observable<Response>;
post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response>;
put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response>;
delete(url: string, options?: RequestOptionsArgs): Observable<Response>;
patch(url: string, body: any, options?: RequestOptionsArgs): Observable<Response>;
head(url: string, options?: RequestOptionsArgs): Observable<Response>;
Each method takes a url and a payload as the case may be, and returns a generic type of response that can be observed.
Let's see one example, here's our note model.
export class Note {
constructor(
public id: Date,
public author: string,
public text:string
){}
}
Now let's try to create a simple service class that will allow an http request to get data from the server.:
import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Note } from '../model/note';
import {Observable} from 'rxjs/Rx';
// Import RxJS required methods
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
@Injectable()
export class NoteService {
// Resolve HTTP using the constructor
constructor (private http: Http) {}
// private instance variable to hold base url
private noteUrl = 'http://localhost:8000/api/notes;
// Fetch all existing notes
getNotes() : Observable<Note[]> {
// ...using get request
return this.http.get(this.notesUrl)
// ...and calling .json() on the response to return data
.map((res:Response) => res.json())
//...errors if any
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));
}
}
We call this method to pass the basic url, since this is the endpoint for a list of comments Use the http instance.
This observable is cold, which means it's not pushing out data at the moment.
What is left to be done is to subscribe to the data that can be observed and link it to the views.
Let’s build our components. Time to tie things together. We can now build components that tie both together to make the application usable.
// Imports
import { Component, OnInit, Input, OnChanges } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Note } from '../model/note';
import {NoteService} from '../services/note.service';
// Component decorator
@Component({
selector: 'note-list',
template: `
<h1>note-list</h1>
<ul>
<li *ngFor="let note of notes" >
{{ [note]="note">}}
</li>
</ul>
})
// Component class
export class NoteListComponent implements OnInit, OnChanges{
// Local properties
notes: Note[];
// Constructor with injected service
constructor(private noteService: NoteService) {}
ngOnInit() {
// Load notes
this.loadNotes()
}
loadNotes() {
// Get all notes
this.noteService.getNotes()
.subscribe(
notes => this.notes = notes, //Bind to view
err => {
// Log errors if any
console.log(err);
});
}
}
No one can hear you stream in RxJS land unless you subscribe. By calling a subscription to an observable one:
- It transforms the observable to hot so it begins to produce data
- We pass the callback function, so we react when anything is pushed to the final stream in the observable chain.
In the above implementation, we call loadCommets OnInit by overriding ngOnInit, which has a subscriber that can make an api call to your server through http and load comments into a module that can then be mapped to the UI model.
Isn’t it Awesome!
We can do more with Observable, we can create our own observable that can be used to help Component Interaction You can easily create multiple subscriptions on the same observable.
At this point, you should have a fair understanding of the basics about observable, observers and subscriptions.
Some of these commonly used operators of observable are:
- Map
- Filter
- distinct
Next we will see RxJS Subject