Angular Material mat-slide-toggle组件[checked]属性绑定不生效问题
问题根源
你遇到的现象是多重状态控制逻辑优先级冲突导致的,mat-slide-toggle的状态控制有明确的优先级规则:formControl/formControlName(响应式表单)> ngModel(模板驱动表单)> 独立[checked]属性绑定,低优先级的绑定会被高优先级逻辑完全覆盖,不生效。
你两处写法都犯了重复绑定的问题:
- 第一个业务代码同时声明了
formControlName="enableSynchronization"和[checked]绑定,[checked]的优先级低于表单控件,完全不会生效,开关状态完全由表单控件的值决定 - 测试代码同时声明了
[(ngModel)]和[checked],同理[checked]会被ngModel覆盖,点击开关时组件直接修改ngModel绑定的变量,所以你就算写了[checked]也不会生效
另外mat-slide-toggle的默认交互逻辑是:点击时先切换自身显示状态,再触发(change)事件,所以你就算没修改绑定的状态值,开关也会先切状态,如果你没有把状态改回去的逻辑,就会出现显示状态和业务变量不一致的情况。
解决方法
场景1:使用响应式表单(带formControlName的业务代码)
- 完全删除
[checked]绑定,所有状态同步都通过表单控件实现:当synchronizationState变更时,手动更新表单控件的值即可同步开关状态:
// synchronizationState变更时执行 this.yourForm.get('enableSynchronization').setValue( this.synchronizationState === 'ENABLED', { emitEvent: false } // 加这个参数避免触发多余的change事件 )
- 如果要实现「点击后先弹确认框,用户确认才变更状态」的需求,在确认弹窗的取消回调里把表单控件的值改回原值即可:
openConfirmSynchronizationStateDialog(newChecked: boolean) { const dialogRef = this.dialog.open(ConfirmDialog); dialogRef.afterClosed().subscribe(confirmed => { if (!confirmed) { // 用户取消,把表单值改回原来的,开关状态会自动同步 this.yourForm.get('enableSynchronization').setValue(!newChecked, {emitEvent: false}); return; } // 用户确认,执行后续状态修改逻辑 }) }
场景2:仅用模板绑定(你的测试代码场景)
不要同时使用[(ngModel)]和[checked],二选一即可:
- 用双向绑定的话直接保留
[(ngModel)],删掉[checked],所有状态修改都操作checked变量即可 - 要完全手动控制状态的话,删掉
[(ngModel)],只保留[checked]加(change)事件:
<mat-slide-toggle [checked]="checked" (change)="onToggle($event)"></mat-slide-toggle>
onToggle(event: MatSlideToggleChange) { // 只有符合条件的时候才修改checked的值,否则开关状态不会变 if (/* 你的判断条件 */) { this.checked = event.checked; } }
内容的提问来源于stack exchange,提问作者Tristan MARIE
相关产品推荐
相关产品推荐

