Angular 2 Observable with multiple subscribers

I encountered a similar problem and solved it using Aran’s suggestion to reference Cory Rylan’s Angular 2 Observable Data Services blog post. The key for me was using BehaviorSubject. Here’s the snippets of the code that ultimately worked for me.

Data Service:

The data service creates an internal BehaviorSubject to cache the data once when the service is initialized. Consumers use the subscribeToDataService() method to access the data.

    import { Injectable } from '@angular/core';
    import { Http, Response } from '@angular/http';

    import { BehaviorSubject } from 'rxjs/BehaviorSubject';
    import { Observable } from 'rxjs/Observable';

    import { Data } from './data';
    import { properties } from '../../properties';

    @Injectable()
    export class DataService {
      allData: Data[] = new Array<Data>();
      allData$: BehaviorSubject<Data[]>;

      constructor(private http: Http) {
        this.initializeDataService();
      }

      initializeDataService() {
        if (!this.allData$) {
          this.allData$ = <BehaviorSubject<Data[]>> new BehaviorSubject(new Array<Data>());

          this.http.get(properties.DATA_API)
            .map(this.extractData)
            .catch(this.handleError)
            .subscribe(
              allData => {
                this.allData = allData;
                this.allData$.next(allData);
              },
              error => console.log("Error subscribing to DataService: " + error)
            );
        }
      }

      subscribeToDataService(): Observable<Data[]> {
        return this.allData$.asObservable();
      }

      // other methods have been omitted

    }

Component:

Components can subscribe to the data service upon initialization.

    export class TestComponent implements OnInit {
      allData$: Observable<Data[]>;

      constructor(private dataService: DataService) {
      }

      ngOnInit() {
        this.allData$ = this.dataService.subscribeToDataService();
      }

    }

Component Template:

The template can then iterate over the observable as necessary using the async pipe.

    *ngFor="let data of allData$ | async" 

Subscribers are updated each time the next() method is called on the BehaviorSubject in the data service.

Leave a Comment