Angular Observables And Rxjs Basics Complete Guide

 Last Update:2025-06-22T00:00:00     .NET School AI Teacher - SELECT ANY TEXT TO EXPLANATION.    6 mins read      Difficulty-Level: beginner

Understanding the Core Concepts of Angular Observables and RxJS Basics

Angular Observables and RxJS Basics: A Comprehensive Guide

Angular applications can handle asynchronous operations effectively using Reactive Extensions for JavaScript (RxJS). At the core of this technique are Observables, which provide a powerful way to work with data streams. This approach is particularly useful for handling events, HTTP requests, and other asynchronous activities in modern web applications.

What are Observables?

An Observable is a data stream provider that emits values over time. It's similar to promises in JavaScript but can emit multiple values and provide additional functionalities such as chaining methods for transformation and filtering. Observables can be used for a variety of purposes, including managing UI state changes, processing user inputs, and consuming APIs.

Creating Observables

To make use of observables, you need to create them first. You can create an observable from various sources using the Observable constructor. Here’s how:

import { Observable } from 'rxjs';

const numbers$ = new Observable<number>(subscriber => {
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  setTimeout(() => subscriber.next(4), 1000);
});

numbers$.subscribe(x => console.log(x)); // prints: 1 2 3 4 after 1 second

This example creates an observable, numbers$, that emits four numeric values: 1, 2, and 3 immediately, and 4 after a delay of one second. The $ symbol is a common convention among developers to denote variables that store observables.

Subscribing to Observables

Once you have created an observable, you need to subscribe to it to process emitted values. Subscribing to an observable triggers execution and allows you to define callback functions for handling emitted data and errors.

numbers$.subscribe({
  next(num) { console.log('Received number:', num); },
  error(err) { console.error('Error occurred:', err); },
  complete() { console.log('Completed sequence'); }
});

In this example, next() processes data received from the observable, error() handles any errors that occur during execution, and complete() signals when no more data will be emitted.

Operators

RxJS comes packed with powerful operators that can manipulate and transform observables' emitted data. Some commonly used operators include:

  • map: Transforms data emitted by an observable.

    numbers$.pipe(
        map(num => num * 2)
    ).subscribe(num => console.log(num)); // prints: 2 4 6 8
    
  • filter: Filters emitted data based on a condition.

    numbers$.pipe(
        filter(num => num > 2)
    ).subscribe(num => console.log(num)); // prints: 3 4
    
  • concat: Combines two or more observables sequentially.

    import { concat } from 'rxjs';
    
    concat(numbers$,Observable.of(5,6)).subscribe(num => console.log(num));
    // prints: 1 2 3 4 5 6
    
  • merge: Combines observables concurrently, emitting their values as they arrive.

    import { merge } from 'rxjs';
    
    merge(numbers$, Observable.of(5, 6)).subscribe(num => console.log(num));
    // might print: 1 5 2 6 3 4 or 5 1 6 2 3 4 depending on timing
    
  • debounceTime: Ignores source values for a specified duration whenever a new value arrives.

    const input$ = new Observable(e => e.next('input triggered'));
    
    input$.pipe(
        debounceTime(1000)
    ).subscribe(event => console.log(event)); 
    // logs once every second
    
  • catchError: Recovers from an observable error by providing a fallback observable.

    import { throwError } from 'rxjs';
    import { catchError } from 'rxjs/operators';
    
    const observableWithError$ = throwError('Something went wrong');
    
    observableWithError$.pipe(
        catchError(() => {
          return Observable.of('Fallback Value');
        })
    ).subscribe({
      next(val) { console.log(val); }, 
      error(err) { console.error(err); }}); 
    // prints: Fallback Value
    

Unsubscribing from Observables

It's crucial to unsubscribe from observables when they're no longer needed, especially when dealing with long-lived subscriptions like those tied to user interface events. Angular automatically unsubscribes from most observables in components once they're destroyed, but you may need to manually unsubscribe in other scenarios.

const subscription = numbers$.subscribe(x => console.log(x));

// unsubscribe when data processing is complete
subscription.unsubscribe();

Subjects

Subjects are a type of observable that can multicast a single execution to many subscribers. They can act as both observables and observers, accepting emissions via next(), error(), and complete() methods and emitting these to subscribers.

There are several kinds of subjects including:

  • BehaviorSubject: Stores the current value and emits it to all new subscribers. It requires an initial value.

    import { BehaviorSubject } from 'rxjs';
    
    const behaviorSubject = new BehaviorSubject(10);
    
    behaviorSubject.subscribe({
      next(val) { console.log('New behaviorSubject subscription', val); }}); 
    // prints: New behaviorSubject subscription 10
    
    behaviorSubject.next(20);
    // prints: New behaviorSubject subscription 20
    
  • ReplaySubject: Emits recent values to subscribers without a starting point.

    import { ReplaySubject } from 'rxjs';
    
    const replaySubject = new ReplaySubject(2);
    
    replaySubject.next(1);
    replaySubject.next(2);
    
    replaySubject.subscribe({
      next(val) { console.log('ReplaySubject subscription:', val); }}); 
    // prints: ReplaySubject subscription: 1
    // prints: ReplaySubject subscription: 2
    
  • AsyncSubject: Emits only the last value before completion to each subscriber.

    import { AsyncSubject } from 'rxjs';
    
    const asyncSubject = new AsyncSubject();
    
    asyncSubject.next(1);
    asyncSubject.next(2);
    asyncSubject.complete();
    
    asyncSubject.subscribe({
      next(val) { console.log('AsyncSubject subscription:', val); }}); 
    // prints: AsyncSubject subscription: 2
    

Use Cases

Here are some practical examples where observables come in handy:

  1. HTTP Requests: To manage and track the status of API calls, observables simplify handling responses asynchronously.

    import { HttpClient } from '@angular/common/http';
    import { Observable } from 'rxjs';
    
    constructor(private http: HttpClient) {}
    
    fetchData(): Observable<any> {
        return this.http.get('https://api.example.com/data');
    }
    
  2. Component Communication: To share information between components using services, observables provide a decoupled and robust solution.

    // Service file
    import { Injectable } from '@angular/core';
    import { Subject } from 'rxjs';
    
    @Injectable({ providedIn: 'root' })
    export class ShareService {
        private subject = new Subject<any>();
    
        sendMessage(message: any) {
            this.subject.next({ text: message });
        }
    
        clearMessage() {
            this.subject.next(null);
        }
    
        getMessage(): Observable<any> {
            return this.subject.asObservable();
        }
    }
    
    // Subscribing Component
    import { Component, OnInit } from '@angular/core';
    import { ShareService } from './share.service';
    
    @Component({ selector: '...', template: '...' })
    export class ComponentB implements OnInit {
        constructor(private shareService: ShareService) {}
    
        ngOnInit() {
            this.shareService.getMessage().subscribe(message => {
                console.log(message);
            });
    
            this.shareService.sendMessage('Hello From Component B!');
        }
    }
    

Summary

Angular Observables and RxJS form the backbone of reactive programming in Angular applications. Using observables allows developers to manage complex asynchronous flows easily, while RxJS provides a suite of tools for handling and transforming data streams effectively. Understanding this concept is vital for building efficient, scalable, and responsive Angular apps. By leveraging observables and their operators, developers can create robust mechanisms for event handling, data binding, and asynchronous operations, leading to improved app performance and better user experience.

This topic encompasses essential concepts like creating observables, subscribing to them, understanding operators, working with subjects, and best practices around managing subscriptions. Each element plays a pivotal role in mastering reactive programming within the Angular framework.

Online Code run

🔔 Note: Select your programming language to check or run code at

💻 Run Code Compiler

Step-by-Step Guide: How to Implement Angular Observables and RxJS Basics

Step 1: Introduction to Observables and RxJS

Observables are a core concept of RxJS, a library for working with streams of data. An observable is an object that represents a stream of data and can emit events over time.

Step 2: Setting Up Angular Project

First, create a new Angular project:

ng new observable-demo
cd observable-demo

Step 3: Importing RxJS in Angular

RxJS is already included in new Angular projects, so you don't need to install it separately. You can import necessary operators and functions from RxJS.

Step 4: Simple Observable Example

  1. Create a new component:

    ng generate component simple-observable
    
  2. Open simple-observable.component.ts:

    import { Component, OnInit } from '@angular/core';
    import { Observable, Observer } from 'rxjs';
    
    @Component({
      selector: 'app-simple-observable',
      template: `<p>Simple Observable Example</p>`
    })
    export class SimpleObservableComponent implements OnInit {
      ngOnInit(): void {
        // Create an observable instance
        const simpleObservable = new Observable((observer: Observer<number>) => {
          console.log('Simple Observable started');
          observer.next(1);
          observer.next(2);
          observer.next(3);
          observer.complete();
          observer.next(4); // This will not be emitted as the observable has already completed
        });
    
        // Subscribe to the observable
        simpleObservable.subscribe({
          next: (value) => console.log('Received value: ' + value),
          error: (err) => console.log('Something went wrong: ' + err),
          complete: () => console.log('Observable completed')
        });
      }
    }
    
  3. Update app.component.html:

    <app-simple-observable></app-simple-observable>
    
  4. Run the application:

    ng serve
    

    Open your browser and go to http://localhost:4200. Check the browser console for the output.

    Simple Observable started
    Received value: 1
    Received value: 2
    Received value: 3
    Observable completed
    

Step 5: Using Operators

Operators are methods that can be called upon an observable to transform the values emitted by the source observable.

  1. Create another component for operators:

    ng generate component observable-operators
    
  2. Open observable-operators.component.ts:

    import { Component, OnInit } from '@angular/core';
    import { Observable, from } from 'rxjs';
    import { map, filter, tap } from 'rxjs/operators';
    
    @Component({
      selector: 'app-observable-operators',
      template: `<p>Observable Operators Example</p>`
    })
    export class ObservableOperatorsComponent implements OnInit {
      ngOnInit(): void {
        const numbers = from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    
        numbers.pipe(
          filter(num => num % 2 === 0), // Filter even numbers
          map(num => num * 2),          // Multiply by 2
          tap(num => console.log(`Doubled even number: ${num}`)) // Log intermediate values
        ).subscribe(result => console.log('Result:', result));
      }
    }
    
  3. Update app.component.html:

    <app-simple-observable></app-simple-observable>
    <app-observable-operators></app-observable-operators>
    
  4. Run the application again:

    ng serve
    

    Open your browser and check the console for the output:

You May Like This Related .NET Topic

Login to post a comment.