83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
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<string>();
|
|
// Use the input() function instead of the @Input() decorator.
|
|
// input.required makes sure that the menuItems array is always passed.
|
|
menuItems = input.required<MenuItem[]>();
|
|
|
|
// You can also provide a default value with input().
|
|
// In a real app, this would likely come from an authentication service.
|
|
userRoles = input<string[]>(['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));
|
|
}
|
|
}
|