5

In my angular app, I have created an Observable to provide data updates to multiple components. When user clicks on a button, all the Subscribers of the Observable should be updated with different set of data. Below is the code.

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

export class MyService {
private data: number[] = [5,6,7,8];

/// The observable given to outside
private observable: Observable<number[]>;

/// Subscribers of the observable which is given to outside
private subscribers: Map<number, Subscriber<number[]>>;
private nextSubscriberId = 0;

constructor() {
    this.subscribers = new Map();
    this.observable = new Observable(subscriber => {
        const id = ++this.nextSubscriberId;
        this.subscribers.set(id, subscriber);

        subscriber.next(data);

        return () => { this.subscribers.delete(id); };
    });

}

}

At the button click event I do the following

data = [1,2,3,4]; 
this.subscribers.forEach((subscriber, key) => {
    subscriber.next(data);
    });

My question is, Is this the best way of managing subscribers of an Observable ? Are there any alternative ways of handling subscribers instead of managing them by our self ?

dGayand
  • 599
  • 1
  • 7
  • 15

1 Answers1

14

You're basically tying to create your own implementation of Subject. Try this:

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

export class MyService {
  private source = new Subject<number[]>();
  data$ = this.source.asObservable();

  constructor() {}

  next(data: number[]) {
    this.source.next(data);
  }
}

producer.component.ts

class ProducerComponent {
  constructor(private myService: MyService) {}

  ngOnInit() {
    this.myService.next([1,2,3]);
  }
}

consumer.component.ts

class ConsumerComponent {
  constructor(private myService: MyService) {}

  ngOnInit() {
    this.myService.data$.subscribe(data => // ...)
  }
}

If you want to have an initial value in your service, replace:

private source = new Subject<number[]>();

with

private source = new BehaviorSubject<number[]>([1,2,3,4]);, where [1,2,3,4] is the initial value.

Tomasz Kula
  • 16,199
  • 2
  • 68
  • 79
  • Thank you for the prompt reply, I'll try this out. However Is there a way to get notified when someone subscribe/unsubscribe from my Observable? – dGayand Mar 29 '18 at 17:31
  • check out https://stackoverflow.com/questions/47040664/rxjs-get-all-current-active-subscriptions – Tomasz Kula Mar 29 '18 at 17:32
  • if I solved your problem, please consider accepting my answer :) – Tomasz Kula Mar 29 '18 at 17:33
  • Assume if the data that I'm sending out via the Observable is received from an external service. If someone subscribe to my Observable, then I can request data from that external service, and same way when someone unsubscribe, and if there are no more subscribers left, then I can un register from that external service.. How can I do such with this proposed solution ? – dGayand Mar 29 '18 at 17:45