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!
CanActivatelink Interface that a class can implement to be a guard deciding if a route can be activated. If all guards return true , navigation continues. If any guard returns false , navigation is cancelled.
The canActivate guard checks if the user can visit the specific route or we have to prevent access to that specific route. We use the this guard when we have to check some condition and based on that users have the access to reach that specific route or not, before activating the component or showing it to the user.
The Angular CanDeactivate guard is called, whenever we navigate away from the route before the current component gets deactivated. The best use case for CanDectivate guard is the data entry component. The user may have filled the data entry and tries to leave that component without saving his work.
You can use the CanDeactivate guard to prevent usesr from accidentally leaving a route/page in your application for example if such page contains a text editor with unsaved changes or an unsubmitted form.
The Angular CanActivate guard runs before we navigate to a route allowing us to cancel the navigation. In this tutorial, we will learn what is CanActivate guard is and how to use it to protect the route.
If there is no route guard then anyone can access any link but using route guard we restrict the access of links. To achieve route guards, Angular provides following interfaces that are contained in @angular/router package.
The angular Guards are a great tool, which helps us to protect the route. They also help us to run some logic, get data from the back end server, etc. You can also create multiple guards against a single route or use the same guard against multiple routes.
1. CanActivateChild is an Angular interface to guard child routes. Suppose a user has been authenticated but not authorized to visit the child routes, so child routes can be guarded using CanActivateChild. Find its declaration from the Angular doc. Method signature of canActivateChild () is the same as canActivate () .
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
classIf 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