From the Angular documentation on canActivate
, it seems you can only use canActivate
guards to allow proceeding to a route if the canActivate
function ultimately returns true
.
Is there some way to say, "only proceed to this route if the canActivate
class evaluates to false
" ?
For example, to not allow logged in users to visit the log in page, I tried this but it did not work:
export const routes: Route[] = [
{ path: 'log-in', component: LoginComponent, canActivate: [ !UserLoggedInGuard ] },
I got this error in the console:
ERROR Error: Uncaught (in promise): Error: StaticInjectorError[false]:
StaticInjectorError[false]:
NullInjectorError: No provider for false!
Error: StaticInjectorError[false]:
StaticInjectorError[false]:
NullInjectorError: No provider for false!
The interesting thing in your question is the formulation:
Is there some way to say, "only proceed to this route if the canActivate class evaluates to false" ?
And how you expressed the "intuitive" solution:
{ path: 'log-in', component: LoginComponent, canActivate: [ !UserLoggedInGuard ] },
Which basically says, you need to negate
the result of UserLoggedInGuard@canActivate
Lets consider the following implementation of the UserLoggedInGuard
:
@Injectable()
export class UserLoggedInGuard implements CanActivate {
constructor(private _authService: AuthService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
return this._authService.isLoggedIn();
}
}
Next, lets look at the solution proposed by @Mike
@Injectable()
export class NegateUserLoggedInGuard implements CanActivate {
constructor(private _authService: AuthService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
return !this._authService.isLoggedIn();
}
}
Now, the approach is ok, but is tightly coupled to the (internal) implementation of UserLoggedInGuard
. If for some reason the implementation of UserLoggedInGuard@canActivate
changes, NegateUserLoggedInGuard
will break.
How can we avoid that? Simple, abuse dependency injection:
@Injectable()
export class NegateUserLoggedInGuard implements CanActivate {
constructor(private _userLoggedInGuard: UserLoggedInGuard) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
return !this._userLoggedInGuard.canActivate(route,state);
}
}
Now this is doing exactly what you expressed with
canActivate: [ !UserLoggedInGuard ]
And the best part:
UserLoggedInGuard
Guard
class