I know angular route guards execute in the specified order when the canActivate function returns a simple boolean
, however, what if the guards return type Observable<boolean>
or Promise<boolean>
?
Example in route:
{
path: 'confirm',
canActivate: [AuthGuard, SessionExpiredAuthGuard, CheckoutAuthGuard],
component: CheckoutReviewOrderComponent
},
SessionExpiredAuthGuard and CheckoutAuthGuard both return type Observable<boolean>
. I don't want the CheckoutAuthGuard to be executed before the SessionExpiredAuthGuard is finished retrieving it's data from the asynchronous http request.
Is there any way to force these asynchronous guards to execute in order?
Problem
First of all, angular doesn't support the feature to call the guards in tandem. So if first guard is asynchronous and is trying to make ajax calls, all the remaining guards will get fired even before completion of the ajax request in guard 1.
I faced the similar problem and this is how I solved it -
Solution
The idea is to create a master guard and let the master guard handle the execution of other guards.
The routing configuration in this case, will contain master guard as the only guard.
To let master guard know about the guards to be triggered for specific routes, add a
data
property inRoute
.The
data
property is a key value pair that allows us to attach data with the routes.The data can then be accessed in the guards using
ActivatedRouteSnapshot
parameter ofcanActivate
method in the guard.The solution looks complicated but it will assure proper working of guards once it is integrated in the application.
Following example explains this approach -
Example
1. Constants Object to map all application guards -
2. Application Guard -
3. Routing Configuration -
4. Master Guard -
Challenges
One of the challenges in this approach is refactoring of existing routing model. However, it can be done in parts as the changes are non-breaking.
I hope this helps.
In addition to the answer planet_hunter, I dare to share a little improvement master-guard