Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bind 'disabled' property of PrimeNG MenuItem?

I'm developing an application using angular / primeng and came across an issue.

I'm using a primeng TabMenu component and would like some tabs to be disabled depending on whether a user is logged in or not, but I can't for the life of me figure out how to bind a 'disabled' property of a tab to a variable.

Here is my code:

component.html:

<p-tabMenu [model]="items">
</p-tabMenu>

component.ts:

export class TopMenuComponent implements OnInit {

    constructor(private auth: AuthService) { }

    items: MenuItem[];

    ngOnInit() {
        this.items = [
            {label: 'Home', routerLink: '/'},
            {label: 'Tab1',  routerLink: '/tab1'},
            {label: 'Tab2',  routerLink: '/tab2', disabled=!this.auth.isUserLoggedIn},
            {label: 'Tab3',  routerLink: '/tab3'},
        ];

    }
}

where auth.isUserLoggedIn is a boolean changing value depending on user logging in or logging out.

The above of course doesn't work since the 'disabled' property is only set during init to a false value(as expected since user is not logged in yet).

I cannot set 'disabled' to a function or Observable since MenuItem only accepts boolean values.

I actually solved it by creating an observable isUserLoggedInObservable and subscribing to it in ngOnInit() this way:

this.auth.isUserLoggedInObservable.subscribe(value => {
          this.items[2].disabled = !value;
        })

but it feels to me that I must be missing the correct way of solving the issue.

How should it be done correctly?

like image 236
michal_d Avatar asked Jan 02 '26 03:01

michal_d


2 Answers

You should avoid subscribing manually when possible, and if you do then you need to cleanup your subscription. The proper way to solve this is to have the items be an Observable. You then make it depend on the outcome of the isUserLoggedInObservable of the auth service, but kick off the stream with the disabled state like so:

export class TopMenuComponent implements OnInit {
    constructor(private auth: AuthService) {}

    items$: Observable<MenuItem[]>;

    ngOnInit() {
        this.items$ = this.auth.isUserLoggedInObservable.pipe(
          map(isLoggedIn => getMenuItems(isLoggedIn)),
          startWith(this.getMenuItems(false))
        );
    }

    private getMenuItems(isLoggedIn: boolean): MenuItem[] {
      return [
        { label: 'Home', routerLink: '/' },
        { label: 'Tab1',  routerLink: '/tab1' },
        { label: 'Tab2',  routerLink: '/tab2', disabled: !isLoggedIn },
        { label: 'Tab3',  routerLink: '/tab3' },
      ];
    }
}

You can then use the items$ stream in the template with the async pipe:

<p-tabMenu [model]="items$ | async"></p-tabMenu>
like image 84
Joep Kockelkorn Avatar answered Jan 04 '26 23:01

Joep Kockelkorn


The issue is that the menu item does not redender if one of its property change.

You still could solve this using CSS:

  1. create an async conditional ngClass in your html:
<p-sidebar>
    <p-menu [model]="menuItems" [ngClass]="{'authenticated': (authState$ | async)}"></p-menu>
</p-sidebar>
  1. add a styleClass "only-authenticated" to the menu you want to hide:
  menuItems: MenuItem[] = [
    {
      label: 'help',
      icon: 'fal fa-question-circle',
      routerLink: '/help',
      styleClass: "only-authenticated"
    }
...
// import your Observable
  authState$ = this.authService.authState$;

  1. finally add the correct styling to your css:
p-menu:not(.authenticated) {
  // user is not authenticated
  .only-authenticated {
    display: none;
  }
}
like image 45
Moh Avatar answered Jan 04 '26 22:01

Moh



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!