角材料-无法处理多个项目

时间:2019-09-04 19:01:51

标签: javascript html angular angular-material

我正在将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 <app-sidenav-item>

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

屏幕打印

如您所见,我能够在单独的节点上打开多个项目。我无法关闭上一个。另外,它仅响应点击,而不响应鼠标悬停。

enter image description here

1 个答案:

答案 0 :(得分:0)

好吧,这是事情,您必须对数据进行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 };
}

每个项目将包含不同级别的valuelabelparenthasChildren,您可以直接与api连接,以确保传递的对象具有{ {1}}属性,请参阅functon getData

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

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