Search code examples
angularangular-ng-ifrxjs-observables

Observable<string[]> in ngIf directive


I have a method that returns roles of a user like:

  getUserRoles() : Observable<string[]> {
    return this.getToken().pipe(
      map(token => {
        let payload = decode(token);
        return payload["roles"];
      })
    )
  }

I'm trying to use this in an anchor to hide/show the item based on a role like:

<a *ngIf="(authService.getUserRoles | async).includes('admin')" routerLink="/admin" clrDropdownItem>Admin</a>

However, I get the compiler error:

ERROR in src/app/components/profile/profile.component.html:15:18 - error TS2769: No overload matches this call.
  The last overload gave the following error.
    Argument of type '() => Observable<string[]>' is not assignable to parameter of type 'Promise<unknown>'.
      Type '() => Observable<string[]>' is missing the following properties from type 'Promise<unknown>': then, catch, [Symbol.toStringTag], finally

15       <a *ngIf="(authService.getUserRoles | async).includes('admin')" routerLink="/admin" clrDropdownItem>Admin</a>
                    ~~~~~~~~~~~~~~~~~~~~~~~~~

  src/app/components/profile/profile.component.ts:7:16
    7   templateUrl: './profile.component.html',
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~
    Error occurs in the template of component ProfileComponent.

Can't quite figure out what I'm doing wrong. I'm using Angular 9.


Solution

  • Ah, I think I get it!

    I had a somewhat similar problem once, also with a function call in the template. Long story short, change detection triggered change detection, which is more or less while (true);.

    Try changing this

    <a *ngIf="(authService.getUserRoles() | async).includes('admin')" ...
    

    into something like

    <a *ngIf="userIsAdmin" ...
    

    and in the TS part of the component

    userIsAdmin = false;
    onDestroy = new Subject();
    
    ngOnInit() {
        this.authService.getUserRoles().pipe(takeUntil(this.onDestroy)).subscribe(/* assign value to this.userIsAdmin here
    }
    
    ngOnDestroy() {
        /* To prevent a memory leak */
        this.onDestroy.next(); 
        this.onDestroy.complete();
    }