Observables in Angular

Observables in Angular

In Angular, Observables are a foundational mechanism for managing asynchronous data streams and event handling. They offer a powerful, flexible way to react to changing data over time.

 

Key Features of Observables

  • Unlike Promises that emit a single value, Observables can emit multiple values over time — ideal for continuous streams like user input, live data, or WebSockets.
  • Observables are lazy — they only start emitting values when explicitly subscribed to. This improves performance and avoids unnecessary computation.
  • You can unsubscribe from an Observable using .unsubscribe() to clean up resources and prevent memory leaks.
  • Observables leverage the RxJS library, which provides a rich set of operators like: map, filter, debounceTime, mergeMap, etc. These enable powerful, declarative transformations and compositions of data streams.
  • Observables are deeply embedded in Angular’s architecture and power many core features:
  • HttpClient
  • Reactive Forms
  • Router events
  • @Output using EventEmitter
  • WebSocket communication
  • Observables streamline handling of next, error, and complete notifications within a single, cohesive API — making error handling and stream finalization more structured.

Simply:

·       Emit multiple values over time

·       Lazy execution (runs only when subscribed)

·       Cancelable via unsubscribe()

·       Rich with RxJS operators

·       Handles next, error, and complete

·       Core to Angular's async architecture 

When you subscribe to an Observable, you provide up to three callbacks:

next(value)

  • Purpose: Handles each emitted value from the Observable.
  • Use Case: Called every time the Observable produces a value.
  • Example: Receiving user data, form input changes, HTTP success responses.

error(err)

  • Purpose: Called once when an error occurs in the Observable stream.
  • Use Case: Handles issues like HTTP failures, runtime exceptions, or logic errors.
  • Effect: Terminates the Observable—no more values will be emitted after this.

complete()

  • Purpose: Called once when the Observable has finished emitting all values and is done.
  • Use Case: Useful for triggering cleanup or final actions once the stream is complete.
  • Important: Unlike error(), complete() indicates successful completion, not failure.

 

Summary Table

Method

Called When

Stream Ends?

Example Use Case

next()

A new value is emitted

❌ No

New chat message, HTTP data, etc.

error()

An error occurs

✅ Yes

HTTP 404/500, network issue

complete()

Stream ends normally (no errors)

✅ Yes

File upload complete, HTTP done

 

Best Practices

  • Use unsubscribe() or takeUntil() to manage subscriptions.
  • Prefer the async pipe in templates for automatic subscription management.
  • Avoid unnecessary subscriptions—compose, don't nest Observables. 

 

Basic Example: Observable Emitting Values Over Time

import { Observable } from 'rxjs';

 

const obs = new Observable(observer => {

  observer.next("First value");

  setTimeout(() => observer.next("Second value"), 1000);

  setTimeout(() => observer.complete(), 2000);

});

 

obs.subscribe({

  next: val => console.log(val),

  complete: () => console.log("Completed")

});

Output in Console

First value

Second value

Completed

 

Extended Example with Unsubscribe and Error Handling

import { Observable, Subscription } from 'rxjs';

 

const obs = new Observable<string>(observer => {

  observer.next("First value");

 

  const second = setTimeout(() => observer.next("Second value"), 1000);

  const complete = setTimeout(() => observer.complete(), 2000);

 

  // Optional error simulation:

  // const error = setTimeout(() => observer.error("Something went wrong"), 1500);

 

  return () => {

    clearTimeout(second);

    clearTimeout(complete);

    console.log("Unsubscribed and cleaned up");

  };

});

 

const subscription: Subscription = obs.subscribe({

  next: val => console.log("Next:", val),

  error: err => console.error("Error:", err),

  complete: () => console.log("Completed")

});

 

setTimeout(() => {

  subscription.unsubscribe();

}, 1500);

Output in Console

Next: First value

Next: Second value

Unsubscribed and cleaned up

 

Angular Service and Component Example

data.service.ts

import { Injectable } from '@angular/core';

import { Observable } from 'rxjs';

 

@Injectable({

  providedIn: 'root'

})

export class DataService {

  getData(): Observable<string> {

    return new Observable(observer => {

      observer.next("First value");

      const t1 = setTimeout(() => observer.next("Second value"), 1000);

      const t2 = setTimeout(() => observer.complete(), 2000);

 

      return () => {

        clearTimeout(t1);

        clearTimeout(t2);

        console.log("Observable cleaned up");

      };

    });

  }

}

app.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Subscription } from 'rxjs';

import { DataService } from './data.service';

 

@Component({

  selector: 'app-root',

  template: `<p>Check console for output</p>`

})

export class AppComponent implements OnInit, OnDestroy {

  private subscription!: Subscription;

 

  constructor(private dataService: DataService) {}

 

  ngOnInit() {

    this.subscription = this.dataService.getData().subscribe({

      next: val => console.log("Received:", val),

      error: err => console.error("Error:", err),

      complete: () => console.log("Stream completed")

    });

 

    setTimeout(() => {

      this.subscription.unsubscribe();

    }, 1500);

  }

 

  ngOnDestroy() {

    if (this.subscription) {

      this.subscription.unsubscribe();

    }

  }

}

 

Why Use Observables in Angular?

Observables, when combined with RxJS operators, provide a reactive, elegant, and maintainable programming model. They help you build more scalable and readable Angular applications by handling async workflows with precision and declarative logic.

Comments

Popular posts from this blog

Promises in Angular

Mastering Your Angular Workflow: Essential CLI Commands for Efficient Development