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];
}