Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you use Angular's canActivate to negate the result of a guard?

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!
like image 728
CodyBugstein Avatar asked Jan 10 '18 22:01

CodyBugstein


People also ask

What is the use of canActivate in Angular?

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.

What is canActivate guard?

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.

Can you deactivate guard?

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.

Can you disable route Guard example?

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.

What is canactivate guard in angular?

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.

What happens if there is no route guard in angular?

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.

What is the use of angular guards?

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.

What is the difference between canactivatechild and canactivate child in angular?

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 () .


1 Answers

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:

  • It isnt tightly coupled with the internal implementation of the UserLoggedInGuard
  • Can be expanded to manipulate the result of more than one Guard class
like image 155
Jota.Toledo Avatar answered Sep 20 '22 17:09

Jota.Toledo