import { Component, inject, input } from '@angular/core'; import { Router, RouterModule } from '@angular/router'; import { CommonModule } from '@angular/common'; import { SafeHtmlPipe } from '../../pipes/safe-html-pipe'; export interface MenuItem { id?: string; menuText: string; targetUrl?: string; onClick?: (event: MouseEvent, item: MenuItem) => void; roles?: string[]; children?: MenuItem[]; getStyleClass?: (item: MenuItem) => string; isActive?: (item: MenuItem, router: Router) => boolean; svgIcon?: string; } @Component({ selector: 'app-menu', imports: [CommonModule, RouterModule, SafeHtmlPipe], templateUrl: './menu.html', styleUrl: './menu.css', }) export class Menu { title = input(); // Use the input() function instead of the @Input() decorator. // input.required makes sure that the menuItems array is always passed. menuItems = input.required(); // You can also provide a default value with input(). // In a real app, this would likely come from an authentication service. userRoles = input(['admin', 'user']); // Use inject() for dependency injection instead of the constructor. private router = inject(Router); isItemVisible(item: MenuItem): boolean { if (!item.roles || item.roles.length === 0) { return true; } // Access the value of the signal by calling it as a function: this.userRoles() return item.roles.some(role => this.userRoles().includes(role)); } handleItemClick(event: MouseEvent, item: MenuItem): void { if (item.onClick) { item.onClick(event, item); } else if (item.targetUrl) { this.router.navigate([item.targetUrl]); } } getItemStyleClass(item: MenuItem): string { return item.getStyleClass ? item.getStyleClass(item) : ''; } isItemActive(item: MenuItem): boolean { if (item.isActive) { return item.isActive(item, this.router); } if (item.targetUrl) { // router.isActive is a boolean check, perfect for this use case. return this.router.isActive(item.targetUrl, { paths: 'exact', queryParams: 'exact', fragment: 'ignored', matrixParams: 'ignored' }); } return false; } // Helper function to determine if a dropdown should be open by default isSubMenuActive(item: MenuItem): boolean { if (!item.children) { return false; } // Recursively check if any child or grandchild is active return item.children.some(child => this.isItemActive(child) || this.isSubMenuActive(child)); } }