Búsqueda de sitios web

javascript - Menú de material angular anidado dinámicamente


Por favor, díganme cómo puedo resolver el siguiente problema: necesito implementar un menú creado dinámicamente con diferentes niveles de anidación según el objeto del modelo de datos. En este momento, utilizando recursión, logramos crear el menú así, sin embargo, hay un problema al asignar el atributo [matMenuTriggerFor] directamente al submenú. El problema es que todos los submenús posteriores, de hecho, hacen referencia al primero, por lo que cuando se pasa el mouse sobre cualquiera de los submenús, se produce un "cambio" al original (ejemplo en la imagen: menú que incluye elementos: Dispositivo, Extensión, Cola, Miembro de cola (con elementos de submenú)). Así, durante una fracción de segundos, veo el otro marco de submenú (ejemplo en la imagen: submenú Lista agrupada), después de lo cual el primero se activa. Por supuesto, tal vez no hice todo correctamente, así que recurro aquí. Por favor ayúdenme. Gracias a todos.

imenu-item.ts

export interface IMenuItem {
  name: string | string[];
  link: string;
  subItems: IMenuItem[];
}

dynamic-menu.service.ts

import {Inject, Injectable} from '@angular/core';
import {APP_CONFIG_ROUTES} from '../../../config/routes/app.config.routes';
import {IAppConfigRoutes} from '../../../config/routes/iapp.config.routes';
import {IMenuItem} from './imenu-item';
import {_} from '@biesbjerg/ngx-translate-extract/dist/utils/utils';

@Injectable({
  providedIn: 'root'
})
export class DynamicMenuService {
  private readonly appConfig: any;

  constructor(@Inject(APP_CONFIG_ROUTES) appConfig: IAppConfigRoutes) {
    this.appConfig = appConfig;
  }

  getMenuItems(): IMenuItem[] {
    return [
      {
        name: _('labels.device'),
        link: '/' + this.appConfig.routes.device,
        subItems: null
      },
      {
        name: _('labels.extension'),
        link: '/' + this.appConfig.routes.extension,
        subItems: null
      },
      {
        name: _('labels.queue'),
        link: '/' + this.appConfig.routes.queue,
        subItems: null
      },
      {
        name: _('labels.queueMember'),
        link: null,
        subItems: [{
          name: _('labels.fullList'),
          link: '/' + this.appConfig.routes.queueMember.all,
          subItems: null
        }, {
          name: _('labels.groupedList'),
          link: '/' + this.appConfig.routes.queueMember.grouped,
          subItems: [{
            name: 'subName',
            link: 'subLink',
            subItems: [{
              name: 'subSubName1',
              link: 'subSubLink1',
              subItems: null
            }, {
              name: 'subSubName2',
              link: 'subSubLink2',
              subItems: null
            }]
          }]
        }]
      }
    ];
  }
}

dynamic-menu.component.ts

import {Component, Input, OnInit} from '@angular/core';
import {IMenuItem} from './imenu-item';

@Component({
  selector: 'app-dynamic-menu',
  templateUrl: './dynamic-menu.component.html',
  styleUrls: ['./dynamic-menu.component.scss']
})
export class DynamicMenuComponent implements OnInit {
  dynamicMenuItemsData: IMenuItem[];

  constructor(private dynamicMenuService: DynamicMenuService) {
  }

  ngOnInit() {
   this.dynamicMenuItemsData = this.dynamicMenuService.getMenuItems();
  }
}

dynamic-menu.component.html

<div>
  <ng-container [ngTemplateOutlet]="recursiveListMenuItems"
                [ngTemplateOutletContext]="{$implicit: dynamicMenuItemsData}">
  </ng-container>
</div>

<ng-template #recursiveListMenuItems let-listMenuItems>
  <div *ngFor="let menuItem of listMenuItems">
    <ng-container [ngTemplateOutlet]="menuItem.subItems != null ? subMenuItem : simpleMenuItem"
                  [ngTemplateOutletContext]="{$implicit: menuItem}">
    </ng-container>
  </div>
</ng-template>

<ng-template #simpleMenuItem let-menuItemArg>
  <a class="mat-button"
     mat-menu-item
     routerLink="{{menuItemArg.link}}">
    <span>{{menuItemArg.name | translate}}</span>
  </a>
</ng-template>

<ng-template #subMenuItem let-menuItemArg>
  <a class="mat-button"
     mat-menu-item
     routerLink="{{menuItemArg.link}}"
     [matMenuTriggerFor]="subItemsMenu">
    <span>{{menuItemArg.name | translate}}</span>
    <mat-menu #subItemsMenu="matMenu"
              [overlapTrigger]="false">
      <ng-container [ngTemplateOutlet]="recursiveListMenuItems"
                    [ngTemplateOutletContext]="{$implicit: menuItemArg.subItems}">
      </ng-container>
    </mat-menu>
  </a>
</ng-template>

Respuesta #1

Como resultado, resultó que dependía de varios problemas similares con otros. Los ejemplos de AQUÍ (ejemplo de menú anidado dinámico) y de AQUÍ (el problema con mat-menu que se oculta inmediatamente al abrirse) ayudaron a resolverlo (en el último ejemplo fue suficiente con actualizar zone.js mediante npm)

Respuesta #2

Perdón por la respuesta tardía, pero tal vez aún te pueda ser útil.
Escribí una pequeña biblioteca llamada ng-action-outlet que hace eso bastante bien en mi opinión.

Se ve así:

group: ActionGroup;

constructor(private actionOutlet: ActionOutletFactory) {
    this.group = this.actionOutlet.createGroup();

    this.group.createButton().setIcon('home').fire$.subscribe(this.callback);
    this.group.createButton().setIcon('settings').fire$.subscribe(this.callback);
}
<ng-container *actionOutlet="group"></ng-container>

DEMO: https://stackblitz.com/edit/ng-action-outlet-demo?file=src/app/app.component.ts

Artículos relacionados