I am passing a subject as an observable from a service to a resolver. The service may complete the observable when an http request completes or when it finds that the data it needs is cached. In the second case, where the data is cached it looks like the observable completes too early because the route transition does not happen. if i put the requestSubject.complete() inside a setTimeout with some timeout it works but otherwise it doesnt.
//resolve function from resolver
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): any {
const id = +route.paramMap.get('id');
const language = route.queryParamMap.get('language');
const request = this.service.get(id, language);
request.pipe(share()).subscribe(
() => {},
() => { this.router.navigateByUrl(AppRoutingConfig.search); });
return request;
}
//the service get function
get(id: number, language: string): Observable<any> {
const requestSubject = new Subject();
if (!isDataCached(id)) {
const url = `some url`;
const sub = this.http.get(url).subscribe((item: any) => {
requestSubject.next(1);
}, () => {
requestSubject.error(0);
}, () => {
requestSubject.complete();
});
} else {
requestSubject.complete();
}
return requestSubject.asObservable();
}
In your case instead of Subject
you need to use ReplaySubject
, it remembers the last value and will emit it once someone subscribes.
Nevertheless I would change the get()
to use a caching state for the stream.
//resolve function from resolver
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): any {
const id = +route.paramMap.get('id');
const language = route.queryParamMap.get('language');
return this.service.get(id, language).pipe(
catchError(() => {
this.router.navigateByUrl(AppRoutingConfig.search);
return EMPTY; // to suppress the stream
}),
);
}
//the service get function
private readonly cache = new Map(); // our cache for urls
get(id: number, language: string): Observable<any> {
const url = `some url`;
// if we had the id - we return its observable.
if (this.cache.has(id)) {
return cache.get(id);
}
// otherwise we create a replay subject.
const status$ = new ReplaySubject(1);
this.cache.set(id, status$);
this.http.get(url).subscribe(
() => status$.next(),
e => status$.error(e),
() => requestSubject.complete(),
);
return status$.asObservable();
}