如何防止角材料垫菜单关闭?

Posted

技术标签:

【中文标题】如何防止角材料垫菜单关闭?【英文标题】:How to prevent angular material mat-menu from closing? 【发布时间】:2018-04-08 15:24:15 【问题描述】:

我正在角度材料中创建一个日期时间选择器控件,并使用以下代码来执行此操作

<button mat-button [matMenuTriggerFor]="menu">
    <mat-icon>date_range</mat-icon>
    <span>Date Range</span>
</button>
<mat-menu #menu="matMenu">
    <div fxLayout="row">
        <div fxLayout="column">
            <button (click)="setInterval(15)" mat-menu-item>Last 15 minutes</button>
            <button (click)="setInterval(360)" mat-menu-item>Last 6 hours</button>
            <button (click)="setInterval(1440)" mat-menu-item>Last 24 hours</button>
            <button (click)="setInterval(2880)" mat-menu-item>Last 2 days</button>
            <button (click)="setInterval(10080)" mat-menu-item>Last 7 days</button>
            <button (click)="setInterval(-1)" [matMenuTriggerFor]="dateTimeMenu" mat-menu-item>Custom</button>
        </div>
        <mat-menu class="date-range-menu" #dateTimeMenu="matMenu">
            <div fxLayout="row">
                <div fxLayout="column">
                    <b>From</b>
                    <mat-calendar></mat-calendar>
                </div>
                <div fxLayout="column">
                    <b>To</b>
                    <mat-calendar></mat-calendar>
                </div>
            </div>
        </mat-menu>
    </div>
</mat-menu>

目前,当我单击一个按钮时,它会关闭菜单。我知道我们可以对每个 mat-menu-item 执行 $event.stoppropagation() 以防止它关闭。

但我想知道 mat-calendar 是否可以这样做

正如您在上图中看到的,当前当我选择一个日期时,它正在关闭菜单。有没有可能防止这种情况发生?

【问题讨论】:

您好,您成功制作了这样的日期范围选择器吗?我需要一个,但并没有心情重新发明***。 【参考方案1】:

您只需将(click) = "$event.stopPropagation()" 添加到这些日历的父元素即可。如下所示,

<mat-menu class="date-range-menu" #dateTimeMenu="matMenu">
    <div fxLayout="row">
        <div fxLayout="column" (click)="$event.stopPropagation();">
            <b>From</b>
            <mat-calendar></mat-calendar>
        </div>
        <div fxLayout="column" (click)="$event.stopPropagation();">
            <b>To</b>
            <mat-calendar></mat-calendar>
        </div>
    </div>
</mat-menu>

Stackblitz demo.

【讨论】:

似乎效果不佳。单击日期时无法选择日期 它非常适合单个 div,但我想对整个 mat-menu 做同样的事情,这样无论用户在 mat-menu 内单击什么位置,它都不应该关闭,不幸的是 $event.stoppropagation() 不起作用整个菜单 为我工作。我在 mat-menu 中添加了一个包装器 div,并在其上添加了 $event.stoppropagation() mat-menu 中的复选框对我有用,非常感谢 此解决方案的另一个问题是,当您单击父元素上的某个位置时,不会触发来自内部所有元素的 blur 之类的事件。这导致我mat-autocomplete 在父元素上单击其他位置时不会关闭,所以我必须找到另一个解决方案【参考方案2】:

通过返回上一个解决方案,将指令封装在一个方法中允许不关闭菜单并继续执行指令

html 中:

<mat-menu class="date-range-menu" #dateTimeMenu="matMenu">
    <div fxLayout="row">
        <div fxLayout="column" (click)="doSomething($event);">
            <b>From</b>
            <mat-calendar></mat-calendar>
        </div>
        <div fxLayout="column" (click)="doSomething($event)">
            <b>To</b>
            <mat-calendar></mat-calendar>
        </div>
    </div>
</mat-menu>

在 TS:

doSomething($event:any)
    $event.stopPropagation();
    //Another instructions

【讨论】:

【参考方案3】:

如果您想在单击 mat-menu-content 时停止关闭 mat-menu,我确实在锚标记而不是 mat-menu 上添加了 $event.stopPropogation()。 因此,即使单击表单上的任何位置,菜单对话框也不会关闭。

Example:- 
    <mat-menu #nameAndDescriptioContextMenu="matMenu" [hasBackdrop]="false">
         <a (click)="$event.stopPropagation();$event.preventDefault();">
               <div>
                 Form Group Form
               </div> 
         </a> 
    </mat-menu>

【讨论】:

爱它,兄弟。干得好!【参考方案4】:

你有很多选择,我邀请你尝试以下

    <mat-menu [hasBackdrop]="false">
     <div  (click)="$event.stopPropagation()" (keydown)="$event.stopPropagation()">
     ...
     </div>
    </mat-menu>

[hasBackdrop]="false" 如果您想防止在单击框外任意位置时关闭 mat-menu,否则将其删除

【讨论】:

【参考方案5】:

不幸的是,以上答案都不适合我。如果您需要菜单面板比内容宽得多,则没有可以放置"$event.stopPropagation();" 的位置,因此如果您单击 mat-menu-panel 它将关闭。 幸运的是,仍然有一种方法可以避免这种情况,通过“覆盖”click MatMenu 事件。 这里是 stackblitz 的例子,感谢我的同事:https://stackblitz.com/edit/mat-menu-disable-close

ngAfterViewInit() 
    // Inject our custom logic of menu close
    (this.searchMenu as any).closed = this.searchMenu.close = this.configureMenuClose(this.searchMenu.close);
  

private configureMenuClose(old: MatMenu['close']): MatMenu['close'] 
    const upd = new EventEmitter();
    feed(upd.pipe(
      filter(event => 
        if (event === 'click') 
          // Ignore clicks inside the menu 
          return false;
        
        return true;
      ),
    ), old);
    return upd;
  

function feed<T>(from: Observable<T>, to: Subject<T>): Subscription 
  return from.subscribe(
    data => to.next(data),
    err => to.error(err),
    () => to.complete(),
  );

这样,只有在您单击外部(这很容易删除)并且使用触发器时,它才会关闭。 这是我在项目中想要的行为,我希望它对某人有用。

【讨论】:

【参考方案6】:

你可以直接在你的组件中使用这个指令。

在 HTML 中

<mat-menu class="date-range-menu" #dateTimeMenu="matMenu">
    <div fxLayout="row">
        <div fxLayout="column" mat-filter-item>
            <b>From</b>
            <mat-calendar></mat-calendar>
        </div>
        <div fxLayout="column" mat-filter-item >
            <b>To</b>
            <mat-calendar></mat-calendar>
        </div>
    </div>
</mat-menu>

将其保存为 filter.directive.ts 从“@angular/core”导入指令、HostListener、HostBinding;

@Directive(
  selector: "[mat-filter-item]"
)
export class FilterItemDirective 
  @HostListener("click", ["$event"])
  onClick(e: MouseEvent) 
    e.stopPropagation();
    e.preventDefault();

    return false;
  

【讨论】:

以上是关于如何防止角材料垫菜单关闭?的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2材料垫选择以编程方式打开/关闭

可重复使用的角材料垫表

如何使用角材料在具有可扩展行的表中创建嵌套垫表

角材料垫选择样式问题

角材料:垫选择不选择默认

角材料步进器在选择更改之前并防止在某些条件下进行步进更改