You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编程式更改mat-button-toggle-group状态并拦截默认切换行为

MatButtonToggleGroup 拦截默认切换加确认弹窗实现

问题背景

结合确认弹窗修改MatButtonToggleGroup状态时,无法直接阻止组件默认切换行为:MatButtonToggleChange事件未提供preventDefault()方法(组件底层实现了ControlValueAccessor接口),常规写法只能在用户点击弹窗取消按钮时,手动将状态重置为之前的旧值,容易出现UI闪烁。

初始问题代码

HTML 文件

<mat-button-toggle-group [value]="value" (change)="onChange($event)">
  <mat-button-toggle [value]="StatusType.Open">
    Open
  </mat-button-toggle>
  <mat-button-toggle [value]="StatusType.Closed">
    Closed
  </mat-button-toggle>
</mat-button-toggle-group>

TS 文件

@Input() value: StatusType;
@Output() statusChange = new EventEmitter<StatusType>();

onChange(event: MatButtonToggleChange): void {
   const newValue = event.value;

    if (newValue === StatusType.Open) {
      this.statusChange.emit(value);

      return;
    }

    const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
      data: {
        title: 'Confirm status change',
        message: 'Are you sure?',
      }
    });

    dialogRef
      .afterClosed()
      .pipe(
        untilDestroyed(this),
        filter((result) => !!result)
      )
      .subscribe(() => {
        this.statusChange.emit(newValue);
      });
}

实现方案

核心逻辑是放弃在change事件层做拦截,改为在click事件层提前阻止默认行为,用完全受控的绑定值控制组件选中状态,只有用户确认操作后才更新绑定值,从根源避免默认切换触发后再回滚的问题:

  • 移除mat-button-toggle-group上的(change)事件绑定,给每个mat-button-toggle单独绑定点击事件
  • 点击事件触发时先调用preventDefault()和stopPropagation()阻止组件默认的选中切换逻辑
  • 仅当操作不需要确认、或用户点击确认弹窗的同意按钮时,才更新绑定的选中值,组件UI会自动和绑定值保持同步,不需要额外做重置操作

修改后代码

HTML 模板

<mat-button-toggle-group [value]="currentValue">
  <mat-button-toggle 
    [value]="StatusType.Open"
    (click)="onToggleClick($event, StatusType.Open)"
  >
    Open
  </mat-button-toggle>
  <mat-button-toggle 
    [value]="StatusType.Closed"
    (click)="onToggleClick($event, StatusType.Closed)"
  >
    Closed
  </mat-button-toggle>
</mat-button-toggle-group>

TS 逻辑

// 受控的当前选中值,替换原有直接绑定的输入值
currentValue: StatusType;
@Input() set value(val: StatusType) {
  this.currentValue = val;
}
@Output() statusChange = new EventEmitter<StatusType>();

onToggleClick(event: MouseEvent, targetValue: StatusType): void {
  // 拦截默认切换行为
  event.preventDefault();
  event.stopPropagation();

  // 点击项为当前已选中项,直接返回
  if (targetValue === this.currentValue) return;

  // 切换到Open状态无需确认,直接更新
  if (targetValue === StatusType.Open) {
    this.currentValue = targetValue;
    this.statusChange.emit(this.currentValue);
    return;
  }

  // 切换到Closed状态弹出确认框
  const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
    data: {
      title: 'Confirm status change',
      message: 'Are you sure?',
    }
  });

  dialogRef.afterClosed()
    .pipe(
      untilDestroyed(this),
      filter(result => !!result)
    )
    .subscribe(() => {
      // 仅确认后更新值,同步UI状态
      this.currentValue = targetValue;
      this.statusChange.emit(this.currentValue);
    });
}

该实现不会出现先切换再回滚的UI闪烁问题,所有状态变更完全可控,不需要额外写取消后的状态重置逻辑。

内容的提问来源于stack exchange,提问作者Sergiu Molnar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 09:57:32