Search code examples
angulartypescriptrxjsobservablerxjs-observables

return a shared Observable from a service


How can I return a shared observable from a services' method? I want to get only one call to the request and share it between subscribers. I can get the expected result if I assign the method to a public field but then I cannot pass a param to it.

here is the service:

@Injectable({
  providedIn: 'root',
})
export class FetchService {
  private entries$ = new Subject<number>();

  constructor() {}

  refreshEntries(id: number) {
    this.entries$.next(id);
  }

  getEntries(id = 0) {
    return this.entries$.pipe(
      startWith(id),
      mergeMap((id) => this.requestEntries(id)),
      shareReplay(1), 
    );
  }

  requestEntries(id: number) {
    console.log('requestEntries');
    return of([1, 2, 3]);
  }
}

and the call:

this.entries$ = this.service.getEntries(0); // called with async pipe in template
this.service.getEntries(0).subscribe((entries) => console.log(entries));

I want the console.log('requestEntries') to be called once.

it works if I make it without the getEntries method but then I can pass the id to the call. I've omitted the code with the id for now, as it returns some cached data. Stackblitz


Solution

  • I think this is what you want.

    export class FetchService {
      private entries: Observable<number[]>[] = [];
    
      constructor() {}
    
      refreshEntries(id: number) {
        this.entries[id] = of([1, 2, 3]).pipe(shareReplay(1));
      }
    
      getEntries(id = 0) {
        if(!this.entries[id]){
          this.entries[id] = of([1, 2, 3]).pipe(shareReplay(1));
        }
        return this.entries[id];
      }
    }
    

    This simply creates a shared observable and puts it in a list. It keeps returning this observable until it is refreshed.