如何在按下回车键时阻止Angular Material的 select组件打开?

前端开发 2026-07-09

我在一个 mat-dialog 里面有一个表单,我希望在按下回车键且表单有效时让对话框“提交”,也就是关闭对话框并将表单的值传递给对话框的 afterClose Promise。

不巧的是,我的表单由若干个 mat-select 构成,它们会劫持回车键并用它来打开各自的下拉菜单,我希望不要发生这种情况,但在Material文档中我似乎找不到关闭它的方法(顺便说一句,我还想保留控件其余部分的键盘导航功能)。

我现在为这些下拉框附加一个 keydown 事件处理程序,它会同时检查是否按下回车键以及表单是否有效;如果有效,就使用对话框引用来关闭对话框。

然而,这仍然会在对话框关闭前短暂地打开下拉框。如果表单无效,它也会打开。如何阻止这种行为?

<form mat-dialog-content
      [formGroup]="formGroup">
  <mat-form-field appearance="fill">
    <mat-label>Sprache</mat-label>
    <mat-select formControlName="language"
                (keydown)="submitOnEnter($event)"
                [panelClass]="colorClass()">
      @for (language of languages(); track language.id) {
        <mat-option [value]="language">{{language.title}}</mat-option>
      }
    </mat-select>
  </mat-form-field>
  <!-- There's some more mat-selects following but I'll avoid repetition -->
</form>
<div mat-dialog-actions>
  <button mat-button
          (click)="close()">Abbrechen</button>
  <button mat-raised-button
          [mat-dialog-close]="formGroup.value"
          [disabled]="!formGroup.valid">OK</button>
</div>

以及组件的相关部分:

export class WordDialog implements OnInit {
  protected _dialogRef: MatDialogRef<WordDialog> = inject(WordDialog);

  public readonly languages: WritableSignal<DataEntry[]> = signal([]);

  public formGroup: FormGroup = new FormGroup({ language: new FormControl<DataEntry | undefined>(undefined, Validators.required), /* Some more controls */ });

  ngOnInit(): void {
    // this.languages get set here but how is irrelevant.
  }

  public close(): void {
    this._dialogRef.close();
  }

  public submitOnEnter(event: KeyboardEvent): void {
    if (event.key === 'Enter') {
      event.preventDefault(); // Probably irrelevant, does not prevent select dropdown.

      if (this.formGroup.valid) {
        this._dialogRef.close(this.formGroup.value);
      }
    }
  }
}

解决方案

你可以使用 addEventListener,将 capture 设为 true,以确保你的监听器在 mat-select 正在使用它之前就被调用,然后阻止传播:

private readonly selectElements = viewChildren(MatSelect, {
  read: ElementRef,
});
private readonly selects = viewChildren(MatSelect);

ngAfterViewInit() {
  const selects = this.selects();
  this.selectElements().forEach((select, i) => {
    (select.nativeElement as HTMLElement).addEventListener(
      'keydown',
      (event: KeyboardEvent) => {
        if (
          event.key === 'Enter' &&
          !selects[i].panelOpen &&
          this.formGroup.valid
        ) {
          event.stopPropagation();
          this._dialogRef.close(this.formGroup.value);
        }
      },
      { capture: true }
    );
  });
}

完整示例

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章