Reputation: 5389
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.
Upvotes: 1
Views: 883
Reputation: 14679
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();
}
Upvotes: 2
Reputation: 2916
Your approach won't work...
Even if you change your code to this: authService.getUserRoles() | async
Your code won't work because this function would run every time your view is checked and
you will not benefit from the async
pipe, the opposite.
It would be better
1) Subscribe to your data in the initilazition of the component (remember to unsubscribe before you destroy the component).
2) Create new pipe to handle that logic.
3) Use guards.
4) Make the function synchronous:
.ts
isInRole(role: string): boolean {
const token = this.getToken();
const payload = decode(token);
return payload && payload["roles"] && payload["roles"].includes(role);
}
.html
<a *ngIf="isInRole('admin')" routerLink="/admin" clrDropdownItem>Admin</a>
Upvotes: 1