【问题标题】:Angular Materials - can't get multi items to work角材料 - 不能让多个项目工作
【发布时间】:2020-01-07 16:51:49
【问题描述】:

我正在使用 Angular 8 和 Angular Materials 来构建一个多级菜单。我可以通过对每个级别使用递归来使菜单工作。我递归调用显示菜单的每一级的同一指令。

这一切正常,菜单按预期构建。但是,菜单的行为与预期不同。我见过的例子,当你将鼠标悬停在一个项目上时,嵌套项目被打开,如果你离开一个项目,它的子项目被关闭。

比如这是我做的一个简单的版本:

https://stackblitz.com/edit/dynamic-sidenav-multi-level-menu-tvim5b?file=app/app.component.html

问题

我的问题是当我构建菜单时,如果我点击一个项目,孩子就会打开。但是,除非我完全单击菜单,否则我永远无法让孩子关闭。它的行为不像上面的例子。

问题

我怎样才能让我的示例像上面那样,并在项目失去焦点时关闭菜单项(子项)?

信息

我没有将我的具体示例放在 StackBlitz 中,因为我不拥有代码,它需要后端服务来支持实现。

我认为我的问题是因为我正在递归构建菜单项,而 [matMenuTriggerFor] 在下一次递归中引用了菜单。

代码

sidenav-list.component.html

<mat-nav-list>
  <!-- Add the Home item -->
  <a mat-list-item routerLink="/home" (click)="onSidenavClose()"><mat-icon>home</mat-icon><span class="nav-caption">Home</span></a>
  <!-- Recurse over the app-sidenav-item -->
  <app-sidenav-item *ngFor="let item of navItems" [item]="item" [depth]="depth+1" [sidenavClose]="sidenavClose"></app-sidenav-item>
</mat-nav-list>

sidenav-item.component.html &lt;app-sidenav-item&gt;

<div>
    <button mat-button *ngIf="depth === 1" [matMenuTriggerFor]="menu"><mat-icon>play_arrow</mat-icon>{{item.name | titlecase}}</button>
    <button mat-menu-item *ngIf="depth > 1" [matMenuTriggerFor]="menu">{{item.name}}</button>

    <mat-menu #menu="matMenu">
        <button *ngIf="item.actions.getItems" mat-menu-item (click)="onItemSelected(item, 0)"><mat-icon>list</mat-icon>Get Items</button>
        <button *ngIf="item.actions.updateItem" mat-menu-item (click)="onItemSelected(item, 1)"><mat-icon>edit</mat-icon>Update Items</button>
        <button *ngIf="item.actions.addItem" mat-menu-item (click)="onItemSelected(item, 2)"><mat-icon>add</mat-icon>Add Item</button>

        <app-sidenav-item *ngFor="let child of item.children" [item]="child" [depth]="depth+1" [sidenavClose]="sidenavClose"></app-sidenav-item>
    </mat-menu>
</div>

丝网印刷

如您所见,我可以在不同的节点上打开多个项目。我无法关闭前一个。此外,它只响应点击而不是鼠标悬停。

【问题讨论】:

  • 我认为因为您可能会动态地执行此操作,这就是您需要布局整个菜单的原因。悬停时父级不会触发孙子级的关闭,直到父级或子级不同。 dynamic-sidenav-multi-level-menu-uomjrw.stackblitz.io
  • @joyBlanks,感谢您提供的信息。是的,我确实认为这是因为我是动态地做的(我必须这样做,因为它是数据驱动的)。另外,我正在使用递归,因为这样就没有代码重复。但是还是不知道有没有办法解决?或以某种方式关闭子项。
  • 是否有某种方法可以在每次递归时更改菜单名称?我有一个深度值,也许我可以试试? (在想可能是因为所有的菜单名称都一样)。
  • 您可以尝试将它们放入 ngcontainers 或 ngtemplates 并隐藏它们
  • @joyBlanks,谢谢。 html 中的语法会是什么样子?我正在努力理解将#menu="matMenu"[matMenuTriggerFor]="menu" 更改为的内容。

标签: javascript html angular angular-material


【解决方案1】:

好的,事情就是这样,您必须以 2 种方式预处理一些数据,这意味着在您的对象中,您必须知道它是否有子对象以启用更多层次结构级别,并且您需要知道它来自哪个父对象以将其过滤到构建这个

你的 html 应该是这样的。由于您知道您可以进行 3 到 4 个级别,因此您可以为这些级别生成模板并在数据存在时使用它。

还有另一个用于 MatMenu 的 @input,称为 matMenuTriggerData,父级将使用它向子级触发数据。

<button mat-button [matMenuTriggerFor]="level1" [matMenuTriggerData]="getData(null, 1)">Animal index</button>


<mat-menu #level1="matMenu">
  <ng-template matMenuContent let-data="data">
      <ng-template ngFor let-item [ngForOf]="data">
          <button mat-menu-item *ngIf="item.children" [matMenuTriggerFor]="level2"
            [matMenuTriggerData]="getData(item, 2)">{{item.label}}</button>
          <button mat-menu-item *ngIf="!item.children">{{item.label}}</button>
        </ng-template>
  </ng-template>
</mat-menu>

<mat-menu #level2="matMenu">
  <ng-template matMenuContent let-data="data">
    <ng-template ngFor let-item [ngForOf]="data">
      <button mat-menu-item *ngIf="item.children" [matMenuTriggerFor]="level3"
        [matMenuTriggerData]="getData(item, 3)">{{item.label}}</button>
      <button mat-menu-item *ngIf="!item.children">{{item.label}}</button>
    </ng-template>
  </ng-template>
</mat-menu>

<mat-menu #level3="matMenu">
  <ng-template matMenuContent let-data="data">
    <button mat-menu-item *ngFor="let item of data">{{item.label}}</button>
  </ng-template>
</mat-menu>

注意最后一级没有更多的触发器。

您可以为过滤后的数据编写一个函数

getData(selected, requested) {
  return selected ? {
    data:
      this['level' + requested].filter(item => item.parent === selected.value)
  } : { data: this.level1 };
}

每个item都会包含valuelabelparenthasChildren在不同级别,你可以直接与api挂钩,确保传递的对象有data属性,见函数getData

您可以在https://stackblitz.com/edit/angular-yfslub查看此解决方案

希望您可以根据自己的需要进行修改。

【讨论】:

  • 感谢您的上述回答。我很感激你的努力。但是,这对我不起作用,因为我的解决方案是数据驱动的。这意味着它有时可能超过 3 个级别,有时可能更少。
  • 你知道最高等级吗?
  • 我的意思是你必须写代码,这是更多的想法
  • 我不认为它会很大,但我不知道在真实情况下它会是什么。我只是想写这个,以便它可以满足不同的层次。这就是我选择使用递归的原因。
猜你喜欢
  • 2023-03-21
  • 1970-01-01
  • 2018-05-26
  • 2017-08-27
  • 2020-08-07
  • 1970-01-01
  • 2022-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多