RxJS in Angular: Demystifying RXJS And Its Use In Managing Asynchronous Operations
If you are new to Angular (like me), and you have heard of RxJs, you might also be wondering what it really is and how to make use of this library in your Angular app. Well, I was like that too and I had to take my time learning what it is all about.
So let's dive in and see what this guy is...
RxJS (Reactive Extensions for JavaScript) is a library that provides a set of powerful tools for dealing with asynchronous and event-driven programming in Angular applications. At its core, RxJS revolves around Observables, allowing us to represent data streams and events over time. RxJS comes pre-installed with Angular, so you don't need to install it separately. You can start using RxJS directly in your Angular components and services.
Observables and Subscriptions
From the core of RxJS comes two important functionalities; Observables and Subscriptions. An Observable is a representation of a stream that emits data over time. Angular leverages Observables extensively, especially when dealing with HTTP requests, event handling, and state management. So basically, In order to receive the data emitted by an Observable, you need to subscribe to it. Subscribing to an Observable establishes a connection between the Observable and the observer (data consumer).
Now let's see a simple example of an Observable that emits a sequence of numbers:
import { Observable } from 'rxjs';
const numberObservable$ = new Observable<number>((observer) => {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
});
const subscription = numberObservable$.subscribe({
next: (value) => console.log(value),
complete: () => console.log('Observable completed.'),
});
// Output:
// 1
// 2
// 3
// Observable completed.
That's it! The code above is a simple demonstration of creating and subscribing to an Observable that emits a sequence of numbers and then logs those numbers to the console. Here's a step-by-step breakdown of the code and its output:
We created an Observable called
numberObservable$
using theObservable
constructor. The Observable emits three values, 1, 2, and 3, and then completes the stream.We subscribed to the
numberObservable$
using thesubscribe
method. The subscription object contains two properties:next
andcomplete
. Thenext
function handles the emitted values and thecomplete
function is called when the Observable completes.When the
subscribe
method is called, the Observable starts emitting values. Thenext
function logs each emitted value to the console.After the Observable emits all the values and reaches its completion point (via
observer.complete()
), thecomplete
function is called, and the subscription is considered completed.
Let's create another simple project using Angular and demonstrate how to use Observables and other core functionalities from RxJS. We will build a basic "User Management" application that fetches user data from a RESTful API and displays it on the screen. Users can be filtered by their roles, and we'll use RxJS Observables to handle the HTTP requests and implement filtering functionality.
Prerequisites: Make sure you have Angular CLI installed. If not, you can install it globally using npm:
npm install -g @angular/cli
Step 1: Create a New Angular Project
Open a terminal and create a new Angular project using the Angular CLI. Generate a new service called userService
to manage user data and HTTP requests:
ng new user-management-app
cd user-management-app
ng generate service user
Open the generated user.service.ts
file (usually located in the src/app
folder) and update it with the following code:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
interface User {
id: number;
name: string;
email: string;
role: string;
}
@Injectable({
providedIn: 'root',
})
export class UserService {
private apiUrl = 'https://jsonplaceholder.typicode.com/users';
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl);
}
getUsersByRole(role: string): Observable<User[]> {
return this.getUsers().pipe(
map((users) => users.filter((user) => user.role === role))
);
}
}
Step 3: Implement the User Component
Generate a new component called user
:
ng generate component user
Update the generated user.component.ts
file with the following code:
import { Component, OnInit } from '@angular/core';
import { UserService } from '../user.service';
import { Observable } from 'rxjs';
interface User {
id: number;
name: string;
email: string;
role: string;
}
@Component({
selector: 'app-user',
template: `
<h2>Users</h2>
<div *ngFor="let user of users$ | async">
<p><strong>Name:</strong> {{ user.name }}</p>
<p><strong>Email:</strong> {{ user.email }}</p>
<p><strong>Role:</strong> {{ user.role }}</p>
<hr />
</div>
<button (click)="filterByRole('admin')">Show Admins</button>
<button (click)="filterByRole('user')">Show Users</button>
`,
})
export class UserComponent implements OnInit {
users$: Observable<User[]>;
constructor(private userService: UserService) {}
ngOnInit() {
this.users$ = this.userService.getUsers();
}
filterByRole(role: string) {
this.users$ = this.userService.getUsersByRole(role);
}
}
Step 4: Add the HttpClientModule
Open the app.module.ts
file (usually located in the src/app
folder) and import the HttpClientModule
to enable HTTP requests:
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule,
],
})
export class AppModule {}
Step 5: Update the App Component
Update the app.component.html
file (usually located in the src/app
folder) to include the app-user
component:
<app-user></app-user>
Step 6: Start the Development Server
Run the following command in the terminal to start the development server:
ng serve
Now, visit the localhost URL the file is served on in your web browser, and you should see the "Users" heading along with a list of user details fetched from the API. Additionally, two buttons labeled "Show Admins" and "Show Users" allow you to filter the displayed users by their roles.
Conclusion
So that is a really simple and easy demonstration of what RxJS is and how to use it at the very basic level. We've explored how to use Observables and other core functionalities from RxJS in an Angular application. We utilized Observables to manage HTTP requests and implemented filtering functionality based on user roles. RxJS's operators like map
and the async
pipe in Angular templates make it straightforward to work with asynchronous data in a reactive and efficient way. You can build on this example to create more complex applications with richer functionality.
RxJS is a fundamental part of Angular development, providing a powerful and expressive way to handle asynchronous operations. By using Observables and a variety of operators, you can efficiently manage HTTP requests, event handling, and state changes in your Angular applications.
Remember to explore the official RxJS documentation for a comprehensive list of operators and their usage in different scenarios. Happy coding with RxJS and Angular!