[Fixed] How to always keep mat-menu at the same position?

Issue

I have this custom dropdown and I’m using mat-checkbox for the items to be selected. Anyway, my issue is that when I open the mat-menu and then I select items (let’s select 2 items) at this time my mat-menu is at a specific position. Now if I close the mat-menu and open it again you’ll see that the mat-menu is at a higher position (it moves like 5px up or so). Does anyone know how to always keep the mat-menu at the same position even after selecting items? Thanks a lot in advance.

NOTE: I tried using disableOptionCentering but it doesn’t work on mat-menu only on mat-select

Here my LIVE DEMO

<mat-menu #menu="matMenu" class="menu-select">
    <div (click)="$event.stopPropagation()">
        <ng-container *ngTemplateOutlet="chipList">
        </ng-container>
        <div *ngFor="let topping of toppingList">
            <mat-checkbox [checked]="listOfItems && listOfItems.indexOf(topping)>=0"
                (change)="change(topping,$event.checked)">
                {{topping}}
            </mat-checkbox>
        </div>
    </div>
</mat-menu>

Solution

Debugging your code in stackblitz shows that you change the chip list in each selecting, leading to the recalculation of the dropdown panel height and position.
So the problem is more of a XY problem.
The code needs some refactoring of the array where you keep values. And use a pipe instead of a method that will be run on each click and reorder the ngFor.
So here is my approach.

Typescript:

...
  toppingList = [
    { item: "item 1", selected: false },
    { item: "testing abc", selected: false },
    { item: "item 3", selected: false },
    { item: "Pepperoni", selected: false },
    { item: "Sausage", selected: false },
    { item: "Tomato", selected: false }
  ];
...



import { Pipe, PipeTransform } from "@angular/core";
@Pipe({
  name: "myFilter",
  pure: false
})
export class MyFilter implements PipeTransform {
  transform(myArray: any[]) {
    return myArray.filter(item => item.selected);
  }


}

HTML:

<mat-menu #menu="matMenu" class="menu-select">
    <div (click)="$event.stopPropagation()">
        <ng-container *ngTemplateOutlet="chipList">
        </ng-container>
        <div *ngFor="let topping of toppingList">
            <mat-checkbox [checked]="topping.selected"
                (change)="topping.selected=!topping.selected">
                {{topping.item}}
            </mat-checkbox>
        </div>
    </div>
</mat-menu>
<ng-template #chipList>
    <mat-chip-list aria-label="Fruit selection">
        <mat-chip *ngFor="let fruit of (toppingList|myFilter)" removable="true">
            {{fruit.item}}
            <mat-icon matChipRemove (click)="fruit.selected=false">cancel</mat-icon>
        </mat-chip>
    </mat-chip-list>
</ng-template>

In this demo you can see that the menu always stays at the same position without any styling needed. Your code will be much lighter and readable

Leave a Reply

(*) Required, Your email will not be published