0

In my angular application I have a service that loads data from a server.

load.service.ts:

load = new Observable(observer => {
  console.log('load function called');
  // async stuff that takes time

  observer.complete();
});

I also have a bunch of components that all need to wait until the load observable completes. I do this like this:

this.loadService.load.subscribe(
  change => {},
  error => {},
  () => {
    // do stuff with data
  }
);

However, if I have multiple components all subscribing, the load function gets called multiple times, sending lots of requests to the server (as seen by console.log('load function called');.

My Question

I know there are ways to get around this using Angular, but my question is this:

How do I have multiple subscriptions to one observable but only call the function once?

My question is not about caching data. It is about observables.

krummens
  • 837
  • 2
  • 17
  • 38
  • Possible duplicate of [Angular 2 cache observable http result data](https://stackoverflow.com/questions/41554156/angular-2-cache-observable-http-result-data) – jonrsharpe Jul 13 '17 at 20:12
  • @jonrsharpe my question isn't about caching data. It's about observables – krummens Jul 13 '17 at 20:13
  • Please read my answer, I think you'll find it applies well to your situation too. You want multiple subscribers to one data source, which isn't unlike caching. – jonrsharpe Jul 13 '17 at 20:14
  • I did read your answer and it doesn't apply to my question. I used the `load` function as an example of how my question applies. I just want to know if it is possible to subscribe to a function without calling it multiple times – krummens Jul 13 '17 at 20:23
  • Well, then: no, of course not. You can't *"subscribe to a function"*. You can *call* a function, and subscribe to what it *returns*. With observables you can pass what it returns to other things, and *they* can subscribe too. But the point of the pattern I've shown is that you separate the trigger and the subscription, so you can fetch data once and easily subscribe from multiple places. You can also re-fetch from somewhere, and all subscribers get the new data when it arrives. – jonrsharpe Jul 13 '17 at 20:25
  • Also you've accepted an answer that suggests using subjects, as I did. – jonrsharpe Jul 13 '17 at 20:54

3 Answers3

2

You have to understand how observables work. load is "cold", it means that new sequence will be started for each subscribe. You need to use share operator to make it "hot" and store somewhere reference to resulting observable:

 public load(){
      if(this.completed){
         this.shared = new Observable(...).share();
         this.shared.subscribe(()=> this.completed = true);
         this.completed = false;
      }
      return this.shared;
 }
kemsky
  • 14,727
  • 3
  • 32
  • 51
2

Why not use BehaviourSubject to store what retuns from the loadService load method and subscribe to the BehaviourSubject. It should solve your problem. Angular 2 Brhaviour Subject vs Observable

Prav
  • 2,785
  • 1
  • 21
  • 30
0

RxJs have share() method. See RxJs documentation : https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/share.md

Here's another SO post related to this: How to call single ajax request by multiple components parallely in angular2 cli project

Hope that helps

penleychan
  • 5,370
  • 1
  • 17
  • 28