Observables in Angular

πŸš€ Observables in Angular – Complete Beginner’s Guide (with Examples)

πŸ“˜ Introduction

In Angular, Observables are a core mechanism for handling asynchronous data streams. Built on top of the RxJS library, they help you react to changes over time—ideal for things like HTTP calls, form inputs, and real-time data updates.



πŸ“š Table of Contents

✨ Key Features of Observables

  • ✅ Emit multiple values over time
  • ⏱ Lazy execution – runs only when subscribe() is called
  • 🚫 Cancelable using unsubscribe()
  • πŸ”§ Works with RxJS operators like map, filter, debounceTime
  • πŸ“¦ Used in Angular’s core: HttpClient, Router, Forms
  • 🧠 Handles next, error, and complete

πŸ” Observable Lifecycle

+----------+ +-----------+ +-------------+ | next() | --> | error() | --> | complete() | +----------+ +-----------+ +-------------+

🧩 Observable Callbacks

  • next(value): Triggered when a value is emitted
  • error(err): Triggered when an error occurs (e.g. 404 error)
  • complete(): Triggered when the stream finishes

⚙️ RxJS Operator Chaining Example

import { of } from 'rxjs';
import { map, filter } from 'rxjs/operators';

of(1, 2, 3, 4).pipe(
  filter(x => x % 2 === 0),
  map(x => x * 10)
).subscribe(value => console.log(value));

Output: 20, 40

Tip: Operator chaining with pipe() makes complex logic easier to manage and test.

πŸ“Š Stream Lifecycle Table

Method When Called Ends Stream? Example Use Case
next() Value emitted User input, HTTP response
error() Error occurs Network failure
complete() Stream ends cleanly File upload finished

✅ Best Practices

  • πŸ” Always unsubscribe manually or use takeUntil()
  • πŸ’‘ Use the Angular async pipe for auto-subscription
  • 🧱 Avoid nested subscriptions; use switchMap or mergeMap

πŸ’» Basic Example

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: First value → Second value → Completed

πŸ§ͺ Extended Example with Error & Unsubscribe

import { Observable, Subscription } from 'rxjs';

const obs = 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("Unsubscribed");
  };
});

const subscription = obs.subscribe({
  next: val => console.log("Next:", val),
  error: err => console.error("Error:", err),
  complete: () => console.log("Stream completed")
});

setTimeout(() => subscription.unsubscribe(), 1500);

πŸ“¦ 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("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() {
    this.subscription.unsubscribe();
  }
}

🎯 Why Use Observables?

Observables bring power and flexibility to async programming. Combined with RxJS, they simplify handling events, HTTP calls, and time-based workflows in Angular.

πŸ”— Resources

Comments

Popular posts from this blog

Debouncing & Throttling in RxJS: Optimizing API Calls and User Interactions

Promises in Angular

Comprehensive Guide to C# and .NET Core OOP Concepts and Language Features