I'm using the Observable<boolean>
return for canActivate()
.
The following function was set up for testing, and it resolves correctly, the component displays.
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return Observable.from([{ admin: true }]).map(x =>
{
if (x.admin) return true;
return false;
});
}
However, the behavior of the actual code is that I stay on the login component despite the console output indicating the route should activate. The only real difference to the test above is I'm calling a service this.auth.isAdmin()
instead of using Observable.from
. The result of this.auth.isAdmin()
is an Observable<boolean>
with a value of true.
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
const isAdmin$ = this.auth.isAdmin();
return isAdmin$.map(x =>
{
console.log('isAdmin returned ' + x);
if (!x) {
console.log('redirectToLogin');
this.auth.redirectToLogin(state.url);
return false;
} else {
console.log('canActivate = true');
return true;
}
});
}
Here is the routing:
{
path: 'admin',
canActivate: [AdminGuard],
children: [
...adminRoutes
]
},
Here is my console output:
isAdmin returned false
admin-guard.service.ts:27redirectToLogin
auth.service.ts:36 navigating to stored path "/admin"
auth.service.ts:21 Object {isAdmin: true, isPaid: false, $key: "xYFs8kMDpKdYKxDw4AL21FtnSWn1"}
admin-guard.service.ts:25 isAdmin returned true
admin-guard.service.ts:31 canActivate = true
And here is the isAdmin() function in case that is of interest:
isAdmin(): Observable<boolean> {
if (!this.auth) return Observable.from([false]);
const uid = this.auth.uid;
return this.af.database.object(`user/${uid}`).do(x => console.log(x)).map(x => x.isAdmin);
}
The observable returned by your isAdmin
function does not complete. AngularFire2 FirebaseObjectObservable
instances do not complete; they emit objects as the underlying data changes.
Observables returned by guards have to complete. You can ensure this by using first
(or take(1)
) to complete the observable when the first value is emitted:
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> {
const isAdmin$ = this.auth.isAdmin();
return isAdmin$.first().map(x =>
{
console.log('isAdmin returned ' + x);
if (!x) {
console.log('redirectToLogin');
this.auth.redirectToLogin(state.url);
return false;
} else {
console.log('canActivate = true');
return true;
}
});
}
At the time of writing, it was necessary for the returned observable to complete. However, Angular now calls first
on the returned observable, so there is no longer a requirement for the observable to complete.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With