Search code examples
angularangular7ngrx-storeangular-changedetection

Public get returns a permission boolean from auth service, which is initialized to false and modified when NGRX store returns a value but is UNDEFINED


I have an Angular7 app and I'm choosing to display a button in app.component based on a boolean that's defined as:

get superUser(): boolean {
    return this.auth.userPermissions.SUPER_USER;
  }

Now in my auth service, I have the userPermissions initialized after the Permissions model with all permissions marked as 'false'.

permissions: Permissions = {
    SUPER_USER: false,
    CLIENT_ADMIN: true,
    ADD_CLIENT: false,
    ADD_USER: false,
    DELETE_CLIENT: false,
    DELETE_USER: false,
    READ_ALL_CLIENTS: false,
    READ_ALL_USERS: false,
    READ_REPORTS: false,
    READ_USERS: false,
    UPDATE_CLIENT: false
  };

  public get userPermissions(): Permissions {
    return this.permissions;
  }

On Authentication, the permissions array is sent to the reducer and permissions are being set with ngrx store.

.subscribe((token: string) => {
            Cookie.set('access_token', token);
            this.store.dispatch(new UserActions.SetUser(this.currentUser));
            const currentUser = this.helper.decodeToken(token);
            this.store.dispatch(
              new PermissionsActions.SetPermissions(currentUser.permissions)
            );
            return this.router.navigate(['']);
          });

In the service, I'm subscribing to that store value and updating the permissions object.

    this.permissionSubscription = this.store
      .select('permissions')
      .subscribe(permissions => {
        this.permissions = permissions;
      });

Now the trouble is, the very first time after authentication the whole thing crashes returning:

Cannot read property 'SUPER_USER' of undefined

Referencing the line where I defined the getter.

But it is defined everywhere. There's not a place in my code I haven't initialized and defined the model variable with the 'false' default.

In my reducer that processes the array of permissions:

  const keys: string[] = Object.keys(state);

  for (const permission of action.permissions) {
    if (keys.includes(permission.name)) {
      state[permission.name] = true;
    } else {
      return console.log('ELSE BLOCK FIRING');
    }
  }

  return tassign(state);

It seems that I forgot to update the model with permissions that were in that array and when the for loop got to that, it made the whole state undefined.


Solution

  • Ended up being reducer shenanigans where a function was trying to do something with a property that didn't exist, messing up the whole object onInit every time.