2

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();
Chrillewoodz
  • 27,055
  • 21
  • 92
  • 175
  • It's a bit hard to follow your structure. Do you think you can make a Plunkr to repro the pb so I can try to help you ? :) – maxime1992 Jan 26 '17 at 10:45
  • @Maxime I would if I had more time at the moment, however I managed to find a decent solution that'll do for now by going in another direction. As you can see in my own answer. – Chrillewoodz Jan 26 '17 at 11:08

2 Answers2

1

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.

witttness
  • 4,984
  • 4
  • 25
  • 24
0

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.

Chrillewoodz
  • 27,055
  • 21
  • 92
  • 175