Angular 2 route guard isn't waiting for value to be set

1.4k Views Asked by At

I've got this route guard which should check the user's role as well as a roleAccess property defined in the route definition.

The problem I'm facing is that .map executes regardless of accounts.isSelfPending, only when that is false (it starts off as null in the @ngrx/store) should it allow .map to run.

How can I achieve this?

EDIT: I realise that my question could be a bit vague, what I need is to wait for the user's information from a /self request that is fired higher up the the component hierarchy, and stored in the store.

The problem now is that the /self request isn't even being fired despite being fired in my DashboardComponent, which in turn holds the AdsComponent as one of it's children in the routing. (Which is the route I'm currently trying to lock with this guard).

Why isn't it even firing the /self request? Which I assume is part of this problem.

return this.store.select('accounts')
  .let((state: Observable<IAccountsStorage>) => state.filter((accounts: IAccountsStorage) => accounts.isSelfPending !== null && accounts.isSelfPending === false)))
  .map((accounts: IAccountsStorage) => {

    this.route.data.subscribe(
      data => {

        if (accounts.self) {

          if (accounts.self.role !== data['roleAccess'] && (data['roleAccess'] !== 0 || data['roleAccess'] !== undefined || data['roleAccess'] !== null)) {
            return this.router.navigateByUrl('admin/dashboard');
          }
          else {
            return true;
          }
        }
      }
    );
  }
).first();
2

There are 2 best solutions below

0
On

After realising that using the store as the middle man was causing too much problems I decided to just call the api directly, ending up with a much clearer guard that actually works as intended.

I figured that this might help someone else so I'll leave the final solution here:

canLoad(): Observable<boolean> {

  return this.accountsApi.getSelf()
    .map(res => {

      if (res.data.role === 1) {
        return true;
      }
      else {
        return this.router.navigate(['admin/dashboard']);
      }
    })
    .catch(err => {
      return this.router.navigate(['admin/dashboard']);
  });
}

However, if someone knows how to solve the question with the original code please provide it as I'm curious how to actually do it using the store.

0
On

I know it's a year later, but I had a similar issue with Stores and Guards in Angular. I think your issue has to do with the State initially having a NULL user object--even if only briefly as you set the user from an existing token.

That NULL comes through first but needs to be filtered out, like this:

canLoad(route: Route): Observable<boolean> | Promise<bolean> | boolean {
    return this.store.select(fromRoot.getUser)
        .filter(user => user != null) // ** THIS IS THE KEY TO SKIP NULL USER **
        .map(user => {
            //code t check user role
        }).take(1); // or .first() -- doesn't seem to be necessary for canActivate guards
}

NOTE: The code above reflects the current way Store code is written--or, at least, it's patterned after how the current ngrx/store 4.x code examples are written, which is a different structure than used in your original question.