Angular15 - canActivate based on values stored in BehaviorSubject in oher service

107 Views Asked by At

I have PermissionsService which stores user's permissions. These are loaded from API by HttpClient after user's successful auth process (after login I call the getUserGroupsWithModelPermissions() which loads user's permission groups, and then I sum these permissions into _resolvedUserPermissions BehaviorSubject)

In every component I need these user's permissions, I subscribe to resolvedUserPermissions$, and after receiving data, I use other methods (ex. resolveModelPermission() where I pass data from subscribe) from ModelPermissionsService to do business logic and it works well.

Example usage in components:

  ngOnInit() {
    this.$permissions = this.permissionsService.resolvedUserPermissions$.subscribe(data => {
      this.canSeeProducts = this.permissionsService.resolveModelPermission(data, 'Products', PermissionScope.Read);
    })
  }

Permissions Service:

export class ModelPermissionService {

  private _resolvedUserPermissions = new BehaviorSubject<ModelFieldPermissions[]>([]); 
  public resolvedUserPermissions$ = this._resolvedUserPermissions.asObservable();

  public getUserGroupsWithModelPermissions(): void {
    this.httpClient.get<ApiResponse<UserGroups[]>>(userEndpoint + '/me/permissions', httpOptions)
    .subscribe({
      next: data => {
        this._resolvedUserPermissions.next(this.sumUserPermissions(data.data));
      },
      error: err => {
        console.error(err);
      }
    })
  }

public resolveModelPermission(userPermissions: ModelFieldPermissions[], modelName: string, permissionScope: PermissionScope):boolean {
    if(userPermissions.length > 0){
      // DO LOGIC HERE
    }
    return false;
  }


}

Now I need to use data from resolvedUserPermissions$ in canActivate method in router guard service but I don't know how to subscribe to this resolvedUserPermissions$?

I need something like this:

canActivate(){
    this.modelPermissionService.resolvedUserPermissions$.subscribe(data =>{
        return this.modelPermissionService.resolveModelPermission(data, 'modelName', scope)
    })
}

All methods I found used pipe+map instead of subscribe but I had no permissions data. Example:

canActivate(){
    return this.getAccess()
}

getAccess(){
    this.permissionsService.resolvedUserPermissions$.pipe(
        map(data =>{
            //here data is empty, no logic to do, because no subscription?
        })
    )
}
2

There are 2 best solutions below

5
Edmunds Folkmanis On BEST ANSWER

Permission Service:

export class ModelPermissionService {

 getUserGroupsWithModelPermissions(): Observable<ModelFieldPermissions[]> {
    this.httpClient.get<ApiResponse<UserGroups[]>>('yourpath', httpOptions)
      .pipe(
        map(data => this.sumUserPermissions(data.data)),
        shareReplay(1), // probably you want to hold and re-use result from api
        tap(data=> concole.log(data)), // DEBUGGING
      );
  }

  resolveModelPermission(data, 'modelName', scope): Observable<boolean> {
    return this.getUserGroupsWithModelPermissions().pipe(
      map(data=> / your code to extract permission from user data /),
    )
  }
}

in Resolver Service:

canActivate() {
    return this.modelPermissionService.resolveModelPermission(data, 'modelName', scope)
      .pipe(
        take(1), // Observable must complete!
        tap(data=> concole.log(data)), // DEBUGGING
      ),
}
1
Antoniossss On

Have you tried this?

canActivate(){
    return this.modelPermissionService.resolvedUserPermissions$.pipe(
         switchMap(data => this.modelPermissionService.resolveModelPermission(data, 'modelName', scope))
    )
}