I have an observable in a service:
hasAccess$: Observable<boolean>;
This gets assigned in a separate component. It has filter()
in it and will never emit false, only true. So if it's false it doesn't emit.
I need to use it in a route guard. So I tried:
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> {
return this.service.hasAccess$.pipe(
defaultIfEmpty(false),
tap(access => {
console.log({access}); // never logs
}),
first()
);
}
defaultIfEmpty()
to ensure a value is emitted tap()
to log if anything happens (it doesn't) first()
because observables returned in guards must complete . I ensured this.service.hasAccess$
gets assigned. It throws an error if it isn't because you can't pipe off undefined. There's no error. Now the weird thing is, this emits false:
return of().pipe(
defaultIfEmpty(false),
tap(access => {
console.log({access});
}),
first()
);
Both are piped to defaultIfEmpty(false)
. Why isn't the guard emitting?
Update : Thanks to @martin for pointing out that defaultIfEmpty()
only emits on completion. Also I realize now that first()
won't make it complete if it doesn't emit anything. I guess I need to figure out how to make it complete when it doesn't emit anything.
You can add startWith(false)
operator to your hasAccess$
observable, so it will always emit something:
hasAccess$: Observable<boolean> = this.someServiceCall().pipe(startWith(false));
Or you can introduce a timeout in the canActivate()
method:
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> {
return this.service.hasAccess$.pipe(
timeout(5000),
first(),
catchError(() => of(false))
);
}
If I were you, I'd use the first method if hasAccess$
is getting its value from a store or a synchronous source, and method 2, if it is making an asynchronous call.
Figured out a solution:
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> {
return this.service.hasAccess$.pipe(
merge(of(false)),
first()
);
}
hasAccess$
, false
, first()
so that if hasAccess$
emits true, it takes it, else if it emits nothing, the guard gets false.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.