Comment créer un menu imbriqué dynamique à partir d'un objet json?
J'ai commencé à utiliser Angular Material Design aujourd'hui pour la première fois et j'essaie de créer des menus imbriqués à l'aide de la conception matérielle. La documentation est assez simple pour les éléments statiques.
Mais je dois créer un menu imbriqué dynamique à partir d'un objet json et je ne trouve aucune solution simple à ce problème. Cela doit juste être d'un niveau profond.
objet json (non gravé dans la pierre):
my_menu = {
'main1': ['sub1', 'sub2'],
'main2': ['sub1', 'sub2'],
}
ce qui générerait quelque chose comme ceci mais de manière dynamique: exemple de résultat attendu chez stackblitz
J'ai essayé de le construire en cours d'exécution *ngFor
_ comme ceci pour le menu principal puis séparé sur chaque sous-menu mais cela a abouti à des erreurs.
<button mat-button [matMenuTriggerFor]="main_menu">My menu</button>
<mat-menu #main_menu="matMenu">
<button *ngFor="let main_item of objectKeys(my_menu)" mat-menu-item [matMenuTriggerFor]="main_item">{{ main_item }}</button>
<button mat-menu-item [matMenuTriggerFor]="main2">main2</button>
</mat-menu>
<mat-menu *ngFor="let sub_menu of objectKeys(my_menu)" #sub_menu="matMenu">
<button *ngFor="let sub_name of sub_menu" mat-menu-item>{{ sub_name }}</button>
</mat-menu>
Je sais que c'est faux mais c'est là que ma compréhension de angular s'est terminée.
objectKeys retourne simplement toutes les clés de l'objet en utilisant Object.keys
qui est chargé à partir du fichier ts.
objectKeys = Object.keys;
PS Je suis assez nouveau pour Angular aussi
La structure suivante devrait fonctionner pour vous:
<button mat-button [matMenuTriggerFor]="main_menu">My menu</button>
<mat-menu #main_menu="matMenu">
<ng-container *ngFor="let mainItem of objectKeys(my_menu)">
<button mat-menu-item [matMenuTriggerFor]="sub_menu">{{ mainItem }}</button>
<mat-menu #sub_menu="matMenu">
<button *ngFor="let subItem of my_menu[mainItem]" mat-menu-item>{{ subItem }}</button>
</mat-menu>
</ng-container>
</mat-menu>
Depuis que j'ai placé sub_menu
dans le modèle incorporé (*ngFor
) nous pouvons utiliser le même nom pour la variable de référence du modèle (#sub_menu
).
Voici un exemple StackBlitz d'une imbrication arbitrairement profonde basée sur JSON (créée par @Splaktar)
La clé de l'imbrication arbitraire est l'auto-référencement menu-item.component:
import {Component, Input, OnInit, ViewChild} from '@angular/core';
import {Router} from '@angular/router';
import {NavItem} from '../nav-item';
@Component({
selector: 'app-menu-item',
templateUrl: './menu-item.component.html',
styleUrls: ['./menu-item.component.scss']
})
export class MenuItemComponent implements OnInit {
@Input() items: NavItem[];
@ViewChild('childMenu') public childMenu;
constructor(public router: Router) {
}
ngOnInit() {
}
}
<mat-menu #childMenu="matMenu" [overlapTrigger]="false">
<span *ngFor="let child of items">
<!-- Handle branch node menu items -->
<span *ngIf="child.children && child.children.length > 0">
<button mat-menu-item color="primary" [matMenuTriggerFor]="menu.childMenu">
<mat-icon>{{child.iconName}}</mat-icon>
<span>{{child.displayName}}</span>
</button>
<app-menu-item #menu [items]="child.children"></app-menu-item>
</span>
<!-- Handle leaf node menu items -->
<span *ngIf="!child.children || child.children.length === 0">
<button mat-menu-item [routerLink]="child.route">
<mat-icon>{{child.iconName}}</mat-icon>
<span>{{child.displayName}}</span>
</button>
</span>
</span>
</mat-menu>