Home > OS >  return a shared Observable from a service
return a shared Observable from a service

Time:10-31

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

CodePudding user response:

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.

CodePudding user response:

You are trying to build some kind of service cache, right? It can be archieved in a different way with Angular, but speaking of your particular requestit can be done this way (demo)

type CacheKey = number;

@Injectable({
  providedIn: 'root',
})
export class FetchService {
  private cache: Record<CacheKey, Observable<any>> = {};
  constructor() {}

  refreshEntries(id: number) {
    this.removeCache(id);
  }

  getEntries(id = 0) {
    return this.getOrCreate(id);
  }

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

  private getOrCreate(id: CacheKey) {
    if (this.cache[id] === undefined) {
      this.cache[id] = this.requestEntries(id).pipe(shareReplay(1));
    }

    return this.cache[id];
  }

  private removeCache(id: CacheKey) {
    delete this.cache[id];
  }
  • Related