Angular 5中json对象的动态嵌套材质菜单

Posted

技术标签:

【中文标题】Angular 5中json对象的动态嵌套材质菜单【英文标题】:Dynamic nested Material menu from json object in Angular 5 【发布时间】:2018-06-17 04:31:20 【问题描述】:

如何从 json 对象创建动态嵌套菜单?

我今天第一次开始使用 Angular Material Design,我正在尝试使用 Material Design 创建嵌套菜单。 documentation 非常直接用于静态内容。

但是我需要从 json 对象创建动态嵌套菜单,我无法在任何地方找到一个简单的解决方案。它只需要一层深。

json 对象(不是一成不变的):

my_menu = 
    'main1': ['sub1', 'sub2'],
    'main2': ['sub1', 'sub2'],

会动态生成类似这样的内容:expected result example at stackblitz

我尝试像这样为主菜单构建它运行*ngFor,然后在每个子菜单上分开,但它以错误结束。

<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>

我知道这是错误的,但这就是我对 angular 的理解结束的地方。

objectKeys 只是使用从 ts 文件加载的 Object.keys 返回对象的所有键。

objectKeys = Object.keys;

PS。我对 Angular 也很陌生

【问题讨论】:

【参考方案1】:

以下结构应该适合您:

<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>

由于我在嵌入模板 (*ngFor) 中放置了 sub_menu,因此我们可以为模板引用变量 (#sub_menu) 使用相同的名称。

Stackblitz Example

【讨论】:

非常感谢您的回答。我将扩展问题,为此,我将与您的名字保持一致。如果我有一个带有 subItem 数组的 mainItem 和一个没有 subItems 的 mainItem 如何以动态方式从没有任何子项的 mainItem 中消失箭头? @yurzui 忽略代码风格,我不得不承认这个解决方案背后的想法很漂亮。为了在顶部使用不同的菜单项类型实现类似的效果,我使用了 TemplateOutlets 和 ngContainers 的组合来结束它,但是这里的这个 sn-p 是重构我的代码的合理理由:) 谢谢! btw...objectKeys...既大胆又令人印象深刻,不错:)【参考方案2】:

Here is a StackBlitz example 基于 JSON 的任意深度嵌套(由@Splaktar 创作)

任意嵌套的关键是自引用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>

【讨论】:

我也在寻找在需要开发的 Angular 6/7 应用程序中构建动态菜单/选项卡。我对 Angular 有一些了解,并且有构建路线(预定义),但还没有使用过 Angular 材料。请告知我们是否需要 Angular 材料来完成这种功能,或者没有它也可以实现它?此外,我需要水平和垂直菜单/子菜单。 我写了一个库来处理菜单的动态渲染,你可以在这里找到它:github.com/klemenoslaj/ng-action-outlet 和演示:stackblitz.com/edit/ng-action-outlet-demo 注意:最好使用 Angular 提供的 ng-container 元素,这样您就不会在菜单的同一个父级中拥有多个 &lt;span&gt; 元素。 这应该被标记为正确答案,你只是用这个实现救了我,我从来没想过在它自己内部调用一个组件。 为了让它在 Angular 10 中工作,我必须将 static: true 添加到 viewChild

以上是关于Angular 5中json对象的动态嵌套材质菜单的主要内容,如果未能解决你的问题,请参考以下文章

Angular 嵌套拖放 / CDK 材质 cdkDropListGroup cdkDropList nested

在angular7中读取复杂的嵌套json对象数组

通过 JSON 更新 Angular 动态组件

如何在 Angular 中为嵌套的 JSON 对象使用搜索过滤器?

Angular HTTP Post 请求,Payload 嵌套在 JSON 对象中

如何从对象类型中动态获取值并在扩展面板角材料中实现?