Aller au contenu principal

Observables in Angular

Observables are a fundamental concept in Angular, based on the RxJS library. They provide a powerful way to handle asynchronous data streams and events.

What is an Observable?​

An Observable is a lazy collection of multiple values over time. Think of it as a stream of data that you can subscribe to and react to changes.

import { Observable } from 'rxjs';

// Creating a simple observable
const observable = new Observable(observer => {
observer.next('Hello');
observer.next('World');
observer.complete();
});

Key Characteristics​

  • Lazy: Observables don't execute until you subscribe to them
  • Cancellable: You can unsubscribe to stop receiving data
  • Composable: You can chain operators to transform data
  • Multi-value: Can emit multiple values over time

Common Use Cases in Angular​

1. HTTP Requests​

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable()
export class DataService {
constructor(private http: HttpClient) {}

getData() {
return this.http.get<any[]>('api/data'); // Returns Observable
}
}

2. Component Usage​

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

@Component({
selector: 'app-data',
template: `<div *ngFor="let item of data">{{item.name}}</div>`
})
export class DataComponent implements OnInit, OnDestroy {
data: any[] = [];
private subscription: Subscription;

constructor(private dataService: DataService) {}

ngOnInit() {
this.subscription = this.dataService.getData().subscribe(
data => this.data = data,
error => console.error(error)
);
}

ngOnDestroy() {
this.subscription.unsubscribe(); // Prevent memory leaks
}
}
@Component({
selector: 'app-data',
template: `<div *ngFor="let item of data$ | async">{{item.name}}</div>`
})
export class DataComponent {
data$ = this.dataService.getData(); // Observable

constructor(private dataService: DataService) {}
}

Common RxJS Operators​

Map - Transform data​

this.dataService.getData().pipe(
map(data => data.filter(item => item.active))
).subscribe(filteredData => console.log(filteredData));

CatchError - Handle errors​

import { catchError } from 'rxjs/operators';
import { of } from 'rxjs';

this.dataService.getData().pipe(
catchError(error => {
console.error(error);
return of([]); // Return empty array on error
})
).subscribe(data => this.data = data);

Debounce - Delay emissions​

import { debounceTime } from 'rxjs/operators';

searchControl.valueChanges.pipe(
debounceTime(300) // Wait 300ms after user stops typing
).subscribe(searchTerm => this.search(searchTerm));

Observable vs Promise​

ObservablePromise
Lazy (cold)Eager (hot)
CancellableNot cancellable
Multiple valuesSingle value
Rich operatorsLimited methods

Best Practices​

  1. Always unsubscribe to prevent memory leaks
  2. Use async pipe when possible
  3. Handle errors with catchError operator
  4. Use takeUntil pattern for component cleanup
  5. Avoid nested subscriptions
// Good: Using takeUntil pattern
private destroy$ = new Subject<void>();

ngOnInit() {
this.dataService.getData().pipe(
takeUntil(this.destroy$)
).subscribe(data => this.data = data);
}

ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}

Observables are essential for building reactive Angular applications and handling asynchronous operations effectively!