11

If i specify three guards on a route, it seems as though all guards are evaluated immediately.

{path: '', component: OptionsComponent, canActivate: [ GuardOne, GuardTwo, GuardThree]}

The problem I have is I don't want GuardTwo to run until GuardOne has finished. Is there any way to achieve this?

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
Thomas Maddocks
  • 1,355
  • 9
  • 24

1 Answers1

14

I don't think that's possible in the 4.1.3. Here is the code that runs the guards:

  private runCanActivate(future: ActivatedRouteSnapshot): Observable<boolean> {
    const canActivate = future._routeConfig ? future._routeConfig.canActivate : null;
    if (!canActivate || canActivate.length === 0) return of (true);
    const obs = map.call(from(canActivate), (c: any) => {
      const guard = this.getToken(c, future);
      let observable: Observable<boolean>;
      if (guard.canActivate) {
        observable = wrapIntoObservable(guard.canActivate(future, this.future));
      } else {
        observable = wrapIntoObservable(guard(future, this.future));
      }
      return first.call(observable);
    });
    return andObservables(obs);
  }

This simplified piece:

// array of all guards
canActivate.map((guard)=>{
     observable = guard.canActivate()
})

runs all guards in a sequence without waiting for the previous to finish.

One possible solution would be to have one service that implements CanActivate and combines other guards:

class Combined {
  constructor(private gA: GuardA, private gB: GuardB) {}

  canActivate(r, s) {
        return gA.canActivate(r, s).then(()=>{ return gB.canActivate() });
  }
}

... 
{path: '', component: OptionsComponent, canActivate: [ Combined ]}
Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • So would it be possible to build them synchronously in a separately service, then map in that service that synchronously builds them? – Z. Bagley Jun 09 '17 at 17:01
  • Solid answer, but do you know when this type of situation is needed? – Z. Bagley Jun 09 '17 at 21:09
  • what do you mean? since you asked the question you probably have such situation :) – Max Koretskyi Jun 10 '17 at 03:55
  • I didn't ask, I was working through an answer for OP when your answer came up and was just curious :) – Z. Bagley Jun 10 '17 at 13:42
  • @Z.Bagley, ah, I see, sorry. Let's ask the OP :) – Max Koretskyi Jun 10 '17 at 13:45
  • @Z.Bagley, In my case , I have a common guard to fetch/validate the token and other guards to check authorization in specific modules only . Is this a valid situation to use these ? – Sachin Feb 28 '18 at 23:54
  • @Sachin Yep yep, this more or less just creates the promise definitions in one file to chain in (rather than building parts of promise chains inside individual guards). Pretty elegant tbh for making clean `canActivate` definitions – Z. Bagley Mar 01 '18 at 01:06