Ngx-admin: Feature, Menu disable, hidden

Created on 6 Jun 2017  路  25Comments  路  Source: akveo/ngx-admin

  • I'm submitting a ...
    [ ] bug report
    [x] feature request
    [ ] question about the decisions made in the repository

  • Do you want to request a feature ?

To make it easier working with the project as starter it would be nice if we have 2 new options in pages.menu.

hidden: true, false

  • Sets the menu point invisible. This makes it easier if we update the project with new versions, so we only have to set the menu points hidden again and don麓t have to delete them from the file.

disable: true

  • Menu points should be written in grey. This would make it possible to show user permisions already in the menu. E.g user X is not allowed to acces dashboard so its written in grey and he can麓t click on it.

I build this ugly by my own, but I麓m sure more people would have a use of it.

  • What is the current behavior?

Pages.menu and pages.routing contain the Pages. To remove one you have to change both files.

enhancement

Most helpful comment

@darklinki Agree, not sure if it's part of the doc . But just to illustrate it, you can hide a menu item like this

{
        path: 'metrics/:id',
        data: {
          menu: {
            title: 'Metrics',
            icon: 'ion-stats-bars',
            hidden:true,
            selected: false,
            expanded: false,
            order: 200,
          }
        }
      },

All 25 comments

Nice suggestions @darklinki,
I have one improvement, if a user is not allowed to access a Menu Entry, this entry should be hidden !

Have a look at #151

Ah thank you @sharath1608 . Would be nice to have this as example in the project. Disaple one entry and set the style different is also working.

@darklinki Agree, not sure if it's part of the doc . But just to illustrate it, you can hide a menu item like this

{
        path: 'metrics/:id',
        data: {
          menu: {
            title: 'Metrics',
            icon: 'ion-stats-bars',
            hidden:true,
            selected: false,
            expanded: false,
            order: 200,
          }
        }
      },

I am implementing user role management, to hide menu entries for unauthorized users.
I will share my contributions as soon as I am done.

@m0uj any update on the role management?

I also need role base manu hidden machanism. @m0uj have you any update

If he doesn麓t replys until next week, I will build a simple one cause I would need it anyway in a few weeks. You guys only need a simple role management or also a login/register system ?

I have the same requirement for the hiding the menu based on user role.
some of the menus are only available for super admin.
I did protect the route, but I need some mechanism to hide the menu as well.
@darklinki do you have any updates?

it is possible to implementate it easy.

First solution, in pages.component ngOnInit()
before you send the array to the service you can manipulate it with your user permissions

Second solution, in the BaMenuService, there are a lot of functions to manipulate the menu like selectMenuItem. easy implement one funktion to skip items

Last solution, implement a function in the itemComponent to hide himself if the user have no permissions

@crossRT I have a working solution, kinda like newmans solution.

I think I read something about this feature in the ngx branch.

this is how I achieve it.
in baMenuService.ts line 111, I change prepared.hidden to true when logged in user doesn't have the role.

// hide menu when user doesn't have the role and permissions.
if (prepared.roles && prepared.roles.length > 0) {
  const role = this.authService.getUser().role;
  if (prepared.roles.indexOf(role) === -1) {
    prepared.hidden = true;
  }
}

and here's the menu:

{
  path: 'user',
  data: {
    menu: {
      title: 'kuber.user',
      icon: 'ion-android-person-add',
      selected: false,
      expanded: false,
      order: 0,
      roles: ['super_admin']
    }
  }
},

@crossRT, Its working like a charm..thanks

disable: true

Menu points should be written in grey. This would make it possible to show user permisions already in the menu. E.g user X is not allowed to acces dashboard so its written in grey and he can麓t click on it.

....Please implement this feature

Hi all, I've tried your solutions with some changes according to my project. It's working but with one major issue in it I'm facing is that I've to refresh browser for menu to hide or show according to user role. My pages-menu.ts file is:

import { NbMenuItem } from '@nebular/theme';
import * as _ from 'lodash';
import decode from 'jwt-decode';

const roles = [1, 2, 3, 4, 5, 6, 7];
const token = localStorage.getItem('auth_app_token');
// decode the token to get its payload
let tokenPayload: any = [];
if (token) {
  tokenPayload = decode(token);
}


export const MENU_ITEMS: NbMenuItem[] = [
  {
    title: 'Utahrunning',
    link: '#',
    children: [
      {
        title: 'Ask An Expert Question',
        icon: 'nb-compose',
        link: '/admin/askquestion',
        hidden: !findRole([1, 2, 7], Number(tokenPayload.userRole)),
      },
  {
    title: 'Dashboard',
    icon: 'nb-home',
    link: '/admin/dashboard',
    hidden: !findRole([1, 2], Number(tokenPayload.userRole)),
    home: true,
  },
  {
    title: 'Settings',
    icon: 'ion-wrench',
    link: '/admin/settings',
    hidden: !findRole([1], Number(tokenPayload.userRole)),
    children: [
      {
        title: 'Search',
        link: '/admin/settings/search',
      },
      {
        title: 'Notification',
        link: '/admin/settings/notification',
      },
    ]
  },
]
},
];

function findRole(allowedRoles, userRole) {
  if (Number.isNaN(userRole)) {
    return false;
  }
  console.log('testing -- ' + userRole);
  return (_.find(allowedRoles, function (
    item: any
  ) {
    return item == userRole;
  })) ? true : false;
}

After login findRole didn't run and I've to refresh browser then correct menu loads up. If I logout and login from different user having different role then it shows menu appeared for previously logged in user and again I've to refresh. How can I handle this or if I'm missing anything? Thanks!

Hi all, I've tried your solutions with some changes according to my project. It's working but with one major issue in it I'm facing is that I've to refresh browser for menu to hide or show according to user role. My pages-menu.ts file is:

import { NbMenuItem } from '@nebular/theme';
import * as _ from 'lodash';
import decode from 'jwt-decode';

const roles = [1, 2, 3, 4, 5, 6, 7];
const token = localStorage.getItem('auth_app_token');
// decode the token to get its payload
let tokenPayload: any = [];
if (token) {
  tokenPayload = decode(token);
}


export const MENU_ITEMS: NbMenuItem[] = [
  {
    title: 'Utahrunning',
    link: '#',
    children: [
      {
        title: 'Ask An Expert Question',
        icon: 'nb-compose',
        link: '/admin/askquestion',
        hidden: !findRole([1, 2, 7], Number(tokenPayload.userRole)),
      },
  {
    title: 'Dashboard',
    icon: 'nb-home',
    link: '/admin/dashboard',
    hidden: !findRole([1, 2], Number(tokenPayload.userRole)),
    home: true,
  },
  {
    title: 'Settings',
    icon: 'ion-wrench',
    link: '/admin/settings',
    hidden: !findRole([1], Number(tokenPayload.userRole)),
    children: [
      {
        title: 'Search',
        link: '/admin/settings/search',
      },
      {
        title: 'Notification',
        link: '/admin/settings/notification',
      },
    ]
  },
]
},
];

function findRole(allowedRoles, userRole) {
  if (Number.isNaN(userRole)) {
    return false;
  }
  console.log('testing -- ' + userRole);
  return (_.find(allowedRoles, function (
    item: any
  ) {
    return item == userRole;
  })) ? true : false;
} 

After login findRole didn't run and I've to refresh browser then correct menu loads up. If I logout and login from different user having different role then it shows menu appeared for previously logged in user and again I've to refresh. How can I handle this or if I'm missing anything? Thanks!

Did you managed to find the issue here - regarding the cached menu on logout and login with another role?

Thanks,
Ovi

Hi @rovidiu did you have a look at https://akveo.github.io/nebular/docs/security/acl-configuration--usage

Because when i look at your code i think you have the wrong approach.

Hi @rovidiu did you have a look at https://akveo.github.io/nebular/docs/security/acl-configuration--usage

Because when i look at your code i think you have the wrong approach.

Hello, I wrote that document, but How to use _*nbIsGranted_ directive for menu?
Same @umairm638 issue, I problem with showing menu during switch user?
Can you show a sample/code to us?

I solved this by creating a menu service:

`import { Injectable } from '@angular/core';
import { NbMenuItem } from '@nebular/theme';
import { NbAccessChecker } from '@nebular/security';

@Injectable({
providedIn: 'root'
})
export class MenuService {
constructor(private accessChecker: NbAccessChecker) { }
findMenuItem(dataToFind:string, menuItems: NbMenuItem[]):NbMenuItem
{
return menuItems.find(t=>t.data == dataToFind);
}

getSubMenuItem = function (data:string, subMenuItems:NbMenuItem[]) {
if (subMenuItems) {
for (var i = 0; i < subMenuItems.length; i++) {
if (subMenuItems[i].data == data) {
return subMenuItems[i];
}
var found = this.getSubMenuItem(data, subMenuItems[i].children);
if (found) return found;
}
}
};

setMenuItemVisibility(dataToFind:string, permission:string, resource:string, menuItems: NbMenuItem[]){
var menuItem = this.getSubMenuItem(dataToFind, menuItems);
console.log('menu searched:' + dataToFind);
console.log('menu found:' + menuItem);
if(menuItem == null)return;
console.log('setting auth for menu:' + menuItem.data);
this.accessChecker.isGranted(permission, resource).subscribe(res=>{ menuItem.hidden = !res });
}

}
`

and used it within pages.component.ts :
`import { Component } from '@angular/core';

import { MENU_ITEMS } from './pages-menu';
import {MenuService} from '../services/menu.service'
import { NbAccessChecker } from '@nebular/security';

@Component({
selector: 'ngx-pages',
template: <ngx-sample-layout> <nb-menu [items]="menu"></nb-menu> <router-outlet></router-outlet> </ngx-sample-layout> ,
})
export class PagesComponent {
menu = MENU_ITEMS;
constructor(
private accessChecker: NbAccessChecker,
private menuService:MenuService){
console.log('menu items auth');
menuService.setMenuItemVisibility('createuser', 'create', 'users', this.menu);
}
}
you should define 'data' property for your menu items like : {
icon: 'nb-plus',
title: 'Create User',
link: '/pages/users/create-user',
data: 'createuser'
},`

i am facing issue with hiding menu,in our project they are five roles,i need hide based on user role,can any one help me with that

Same here, I have to refresh the browser in order to load the correct menu for current user logged.

initMenu() {
    let userRole: string;
    this.roleProvider.getRole().subscribe(role => userRole = role);
    this.pagesMenu
      .getMenu(userRole)
      .pipe(takeWhile(() => this.alive))
      .subscribe(menu => {
        this.menu = menu;
      });
  }

userRole does not change its value when you log in with different user (and different role) unless you refresh the browser.

274

I am using custom authentication. If you want to use NbAccessChecker instead of custom authentication check out the commented code.

I have this in my pages.component.ts

import { Component } from '@angular/core';
import { MENU_ITEMS } from './pages-menu';
import { AuthService } from '../core/auth/services/auth.service';
import { NbAccessChecker } from '@nebular/security';
import { NbMenuItem } from '@nebular/theme';

@Component({
selector: 'ngx-pages',
styleUrls: ['pages.component.scss'],
template: <ngx-one-column-layout> <nb-menu [items]="menu"></nb-menu> <router-outlet></router-outlet> </ngx-one-column-layout> ,
})
export class PagesComponent {

menu = MENU_ITEMS;

constructor(private accessChecker: NbAccessChecker, public auth: AuthService) {

}

ngOnInit() {
this.authMenuItems();
}

authMenuItems() {
this.menu.forEach(item => {
this.authMenuItem(item);
});
}

authMenuItem(menuItem: NbMenuItem) {
if (menuItem.data && menuItem.data['expectedRoles']) {
menuItem.hidden = !this.auth.isAuthorized(menuItem.data['expectedRoles']);

} else {
  menuItem.hidden = true;
}
if (!menuItem.hidden && menuItem.children != null) {
  menuItem.children.forEach(item => {
    if (item.data && item.data['expectedRoles']) {
      item.hidden = !this.auth.isAuthorized(menuItem.data['expectedRoles']);

    } else {
      // if child item do not config any `data.permission` and `data.resource` just inherit parent item's config
      item.hidden = menuItem.hidden;
    }
  });
}

}

// authMenuItem(menuItem: NbMenuItem) {
// if (menuItem.data && menuItem.data['permission'] && menuItem.data['resource']) {
// this.accessChecker.isGranted(menuItem.data['permission'], menuItem.data['resource']).subscribe(granted => {
// menuItem.hidden = !granted;
// });
// } else {
// menuItem.hidden = true;
// }
// if (!menuItem.hidden && menuItem.children != null) {
// menuItem.children.forEach(item => {
// if (item.data && item.data['permission'] && item.data['resource']) {
// this.accessChecker.isGranted(item.data['permission'], item.data['resource']).subscribe(granted => {
// item.hidden = !granted;
// });
// } else {
// // if child item do not config any data.permission and data.resource just inherit parent item's config
// item.hidden = menuItem.hidden;
// }
// });
// }
// }

}

Thanks!

I was able to achieve it by getting the user role with a custom service rather than getRole provided by RoleProvider.

  • users.service.ts
getCurrentUser(): Observable<User> {
    return this.authService.isAuthenticated().pipe(
      switchMap(authenticated => {
        return authenticated ? this.api.getCurrent() : of(null);
      }),
    );
  }
  • pages.component.ts
initMenu() {
    this.usersService.getCurrentUser().subscribe(user => {
      this.pagesMenu
        .getMenu(user.role)
        .pipe(takeWhile(() => this.alive))
        .subscribe(menu => {
          this.menu = menu;
        });
    });
  }

@sharath1608 you saved my day
I was able to dynamically add this HIDDEN attribute on every menu item and their children

Thanks

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tal-shahar picture tal-shahar  路  3Comments

argnist picture argnist  路  4Comments

myurAgarwal picture myurAgarwal  路  3Comments

nfdavenport picture nfdavenport  路  3Comments

mignam picture mignam  路  3Comments