Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug(menu): nested menu issues with recursive ng-template #7542

Closed
cpboyd opened this issue Oct 5, 2017 · 7 comments
Closed

bug(menu): nested menu issues with recursive ng-template #7542

cpboyd opened this issue Oct 5, 2017 · 7 comments
Assignees
Labels
cannot reproduce The team is unable to reproduce this issue with the information provided

Comments

@cpboyd
Copy link

cpboyd commented Oct 5, 2017

Bug, feature request, or proposal:

I've tested with the latest changes from #6766, but this is still not fixed.

What is the expected behavior?

It should be possible to create a nested menu from a JSON object without knowing the menu's depth in advance.

What is the current behavior?

You can't, because the recursive templates seem to cause issues with the nested menu.

What are the steps to reproduce?

Had to use StackBlitz instead of Plunkr, because Plunkr's having issues.

StackBlitz: https://stackblitz.com/edit/angular-material2-issue-7p1tik

Note: Since StackBlitz is using the NPM version, and not the snapshot build, even the non-recursive version requires you to click to expand sub-menus rather than hover.

What is the use-case or motivation for changing an existing behavior?

It'd be nice to be able to define a single JSON object describing a nested menu structure.

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

All.

Is there anything else we should know?

@josephperrott
Copy link
Member

It looks like this is working as of beta.12 as seen here

Are you still seeing this issue?

@josephperrott josephperrott self-assigned this Oct 31, 2017
@josephperrott josephperrott added the cannot reproduce The team is unable to reproduce this issue with the information provided label Nov 2, 2017
@josephperrott
Copy link
Member

Closing as it appears this issue is no longer occuring

@mkoczka
Copy link

mkoczka commented Feb 1, 2018

@josephperrott It does not work in the provided example. Even with the latest version. Can you reopen this one?

@softwareCobbler
Copy link

softwareCobbler commented May 28, 2018

I think the goal is to keep the previous menus on screen, to provide visual guidance to the user about where in the menu they've come from, and also to provide them with the opportunity to go back up the menu hierarchy without closing the menu to reopen at the top-most level.
In the provided example by josephperrott on Oct 31 2017, the "nested template" behavior is not the desired behavior, the different approaches should both behave as the "without nested template" variant does.

@MagnusBrzenk
Copy link

@softwareCobbler The poster isnt trying to hide the previous items in the menu, but trying to be able to generate a menu recursively.

@ivanivanyuk1993axelot
Copy link

ivanivanyuk1993axelot commented Sep 5, 2019

This hack helped me, I didn't spend much time on this answer(have low), hence you will have to understand this to make it work, but still it may help you if you dig in. For angular team: this solution breaks if

<button
          *ngIf="route.items; else withoutItems"
          [matMenuTriggerFor]="matMenuDataSource | getPure:route"
          [ngClass]="{ active: route.hasChildrenThatMatchUrlBS$ | async }"
          mat-menu-item
        >{{ route.text }}</button>

is wrapped in template

Parts of solution:

<ng-container
  *ngFor="let routeWithItems of routeWithItemsListOrderedFromLeafsBS$ | async"
>
  <mat-menu
    #matMenu="matMenu"
    [classList]="'mat-menu--overflow-hidden'"
  >
    <ng-template matMenuContent>
      <ng-container
        *ngFor="let route of routeWithItems.items"
      >
        <button
          *ngIf="route.items; else withoutItems"
          [matMenuTriggerFor]="matMenuDataSource | getPure:route"
          [ngClass]="{ active: route.hasChildrenThatMatchUrlBS$ | async }"
          mat-menu-item
        >{{ route.text }}</button>
        <ng-template #withoutItems>
          <a
            [ngClass]="{ active: route.matchesUrlBS$ | async }"
            [routerLink]="route.action"
            mat-menu-item
          >{{ route.text }}</a>
        </ng-template>
      </ng-container>
    </ng-template>
  </mat-menu>
  {{ matMenuDataSource | setPure:routeWithItems:matMenu }}
</ng-container>

<ng-container
  *ngFor="let route of routeList"
>
  <button
    (click)="matMenuTrigger.openMenu()"
    [ngClass]="{ active: route.hasChildrenThatMatchUrlBS$ | async }"
    mat-menu-item
  >
    <img
      *ngIf="route.imageUrl"
      [src]="'/assets/WMS5-Images/png/' + route.imageUrl + '.png'"
      class="mat-icon"
      style="margin-right: 0"
    >
    <span
      [class.hidden]="!(routeListRootComponent.shouldShowTextBS$ | async)"
      style="margin-left: 16px"
    >{{ route.text }}</span>
  </button>

  <div
    #matMenuTrigger="matMenuTrigger"
    [matMenuTriggerFor]="matMenuDataSource | getPure:route"
    class="mat-menu-positioner"
  ></div>
</ng-container>
private _appendRouteToRouteWithItemsListOrderedFromLeafs(
    route: MainMenuExtended,
    routeWithItemsListOrderedFromLeafs: MainMenuExtended[],
  ) {
    const items = route.items;
    if (items) {
      for (const childRoute of items) {
        this._appendRouteToRouteWithItemsListOrderedFromLeafs(childRoute, routeWithItemsListOrderedFromLeafs);
      }
      routeWithItemsListOrderedFromLeafs.push(route);
    }
  }
  private _getRouteWithItemsListOrderedFromLeafs(
    routeList: Array<MainMenuExtended>,
  ): MainMenuExtended[] {
    const routeWithItemsListOrderedFromLeafs: MainMenuExtended[] = [];

    for (const route of routeList) {
      this._appendRouteToRouteWithItemsListOrderedFromLeafs(route, routeWithItemsListOrderedFromLeafs);
    }

    return routeWithItemsListOrderedFromLeafs;
  }

export class GetPurePipe<RouteType> implements PipeTransform {
  transform(
    matMenuDataSource: MatMenuDataSource<RouteType>,
    route: RouteType,
  ): any {
    return matMenuDataSource.get(route);
  }
}
export class SetPurePipe<RouteType> implements PipeTransform {
  transform(
    matMenuDataSource: MatMenuDataSource<RouteType>,
    route: RouteType,
    matMenu: MatMenu,
  ): any {
    matMenuDataSource.set(route, matMenu);
  }
}

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Oct 6, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cannot reproduce The team is unable to reproduce this issue with the information provided
Projects
None yet
Development

No branches or pull requests

6 participants