Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Route guard method breaking routing

Edit: StackBlitz minimal repro seems to work, so there's something else amiss it seems..

Angular 6.1.3

I have a route that needs to be guarded based on the param slug.

{
  path: 'market/:slug',
  component: MarketComponent,
  canActivate: [RoleGuard],
},

RoleGuard canActivate method:

canActivate(route: ActivatedRouteSnapshot): Observable<boolean> | Promise<boolean> | boolean {
  const market$ = this.marketService.getBySlug(
    route.paramMap.get('slug')
  ); // returns an observable of the corresponding market object

  // Verify the user is authorized to see this market.
  return this.authService.isAuthorized(market);
}

authService.isAuthorized:

isAuthorized(market: Observable<Market>): Observable<boolean> {
  return combineLatest(this.user$, market).pipe(
    map(([user, market]) => {
      // Check roles of the user based on the market's configuration
      return true;
    })
  );
}

I've removed the user/market logic just trying to strip out anything that could be causing problems, but when I return the above method inside canActivate the routing stops. Route trace:

Router Event: NavigationStart
NavigationStart(id: 2, url: '/market/sams-corner-store')
NavigationStart {id: 2, url: "/market/sams-corner-store", navigationTrigger: "imperative", restoredState: null}

Router Event: RoutesRecognized
RoutesRecognized(id: 2, url: '/market/sams-corner-store', urlAfterRedirects: '/market/sams-corner-store', state: Route(url:'', path:'') { Route(url:'market/sams-corner-store', path:'market/:slug') } )
RoutesRecognized {id: 2, url: "/market/sams-corner-store", urlAfterRedirects: "/market/sams-corner-store", state: RouterStateSnapshot}

Router Event: GuardsCheckStart
GuardsCheckStart(id: 2, url: '/market/sams-corner-store', urlAfterRedirects: '/market/sams-corner-store', state: Route(url:'', path:'') { Route(url:'market/sams-corner-store', path:'market/:slug') } )
GuardsCheckStart {id: 2, url: "/market/sams-corner-store", urlAfterRedirects: "/market/sams-corner-store", state: RouterStateSnapshot}

Router Event: ChildActivationStart
ChildActivationStart(path: '')
ChildActivationStart {snapshot: ActivatedRouteSnapshot}

Router Event: ActivationStart
ActivationStart(path: 'market/:slug')
ActivationStart {snapshot: ActivatedRouteSnapshot}

During normal routing more Router events are triggered, but here it just stops. I'm thinking it has something to do with the isAuthorized not emitting anything, but I'm stumped. After the failure, navigating anywhere doesn't do anything; the URL stays the same and nothing else is logged to the console.

At times the method isn't even called, console.log isn't called in the combineLatest/withLatestFrom.

I've tried combineLatest and withLatestFrom with some operator variants to no avail.

like image 307
Phix Avatar asked Oct 14 '25 16:10

Phix


2 Answers

canActivate guard will subscribe on returned Observable and waiting till that Observable is completed, until that moment no other router event will be handled.
Add first() (Rx operator) to the user$ and market$ Observable.
PS instead of combineLatest use forkJoin.

like image 87
Buggy Avatar answered Oct 17 '25 05:10

Buggy


You are doing it right, but a guard requires the observable to complete. So you are stuck waiting for it.

try doing

return this.authService.isAuthorized(market).pipe(
    take(1)
);

this will take the first result and complete, which should fix your problem.

like image 38
Leon Radley Avatar answered Oct 17 '25 05:10

Leon Radley



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!