Role-based Dynamic Menus in Angular (Enterprise)
Role-based Dynamic Menus in Angular (Enterprise)
This Angular setup includes:
- ✅ Roles + Permissions
- ✅ Show/Hide menu items dynamically
- ✅ Works with Angular Material Sidenav
- ✅ Supports nested menus
- ✅ Supports multiple roles
- ✅ Enterprise clean structure
Goal
If user has:
- Admin → show everything
- Manager → show dashboard + reports
- User → show only basic pages
1️⃣ Permission Model (Enterprise)
// permission.model.ts
export type Role = 'Admin' | 'Manager' | 'User';
export type Permission =
| 'DASHBOARD_VIEW'
| 'USERS_VIEW'
| 'USERS_CREATE'
| 'REPORTS_VIEW'
| 'SETTINGS_VIEW';
2️⃣ Menu Model
// menu-item.model.ts
import { Permission } from './permission.model';
export interface MenuItem {
label: string;
icon?: string;
route?: string;
permissions?: Permission[]; // permissions required
children?: MenuItem[]; // nested menus
}
3️⃣ Define Enterprise Menu Config
// menu.config.ts
import { MenuItem } from './menu-item.model';
export const MENU_ITEMS: MenuItem[] = [
{
label: 'Dashboard',
icon: 'dashboard',
route: '/dashboard',
permissions: ['DASHBOARD_VIEW']
},
{
label: 'Users',
icon: 'people',
permissions: ['USERS_VIEW'],
children: [
{ label: 'User List', route: '/users', permissions: ['USERS_VIEW'] },
{ label: 'Create User', route: '/users/create', permissions: ['USERS_CREATE'] }
]
},
{
label: 'Reports',
icon: 'bar_chart',
route: '/reports',
permissions: ['REPORTS_VIEW']
},
{
label: 'Settings',
icon: 'settings',
route: '/settings',
permissions: ['SETTINGS_VIEW']
}
];
4️⃣ Auth / Permission Service
// permission.service.ts
import { Injectable } from '@angular/core';
import { Permission, Role } from './permission.model';
@Injectable({ providedIn: 'root' })
export class PermissionService {
private userRoles: Role[] = [];
private userPermissions: Permission[] = [];
setUserAccess(roles: Role[], permissions: Permission[]) {
this.userRoles = roles;
this.userPermissions = permissions;
}
hasPermission(permission: Permission): boolean {
return this.userPermissions.includes(permission);
}
hasAnyPermission(permissions: Permission[]): boolean {
return permissions.some(p => this.hasPermission(p));
}
isInRole(role: Role): boolean {
return this.userRoles.includes(role);
}
}
5️⃣ Create a Custom Directive (Best Enterprise Way)
This avoids long *ngIf checks in templates.
// has-permission.directive.ts
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
import { Permission } from './permission.model';
import { PermissionService } from './permission.service';
@Directive({ selector: '[hasPermission]' })
export class HasPermissionDirective {
@Input('hasPermission') requiredPermissions: Permission[] = [];
constructor(
private templateRef: TemplateRef,
private viewContainer: ViewContainerRef,
private permissionService: PermissionService
) {}
ngOnInit() {
const canShow = this.permissionService.hasAnyPermission(this.requiredPermissions);
this.viewContainer.clear();
if (canShow) this.viewContainer.createEmbeddedView(this.templateRef);
}
}
6️⃣ Use in Angular Material Menu / Sidenav
// app-sidenav.component.html
{{ item.icon }}
{{ item.label }}
7️⃣ Load Menu in Component
// app-sidenav.component.ts
import { Component } from '@angular/core';
import { MENU_ITEMS } from './menu.config';
@Component({
selector: 'app-sidenav',
templateUrl: './app-sidenav.component.html'
})
export class AppSidenavComponent {
menu = MENU_ITEMS;
}
8️⃣ Enterprise: Filter Menu Items Automatically
Instead of directive in template, filter menu in service before display.
// menu.service.ts
import { Injectable } from '@angular/core';
import { MenuItem } from './menu-item.model';
import { MENU_ITEMS } from './menu.config';
import { PermissionService } from './permission.service';
@Injectable({ providedIn: 'root' })
export class MenuService {
constructor(private permissionService: PermissionService) {}
getMenu(): MenuItem[] {
return this.filterMenu(MENU_ITEMS);
}
private filterMenu(items: MenuItem[]): MenuItem[] {
return items
.filter(item => !item.permissions || this.permissionService.hasAnyPermission(item.permissions))
.map(item => ({
...item,
children: item.children ? this.filterMenu(item.children) : undefined
}))
.filter(item => !item.children || item.children.length > 0);
}
}
// Usage in component
menu = this.menuService.getMenu();
Interview Answer (Perfect)
Q) How do you implement role-based menus in Angular?
- ✅ Store menu items in a config file with required permissions.
- ✅ Backend returns roles/permissions after login.
- ✅ Angular filters menu items based on permissions.
- ✅ UI displays only allowed items using a directive or menu filtering service.
Extra Enterprise Final Touch
Backend should return permissions like:
{
"roles": ["Admin"],
"permissions": ["DASHBOARD_VIEW", "USERS_VIEW", "USERS_CREATE"]
}
Comments
Post a Comment