Angular响应式表单互斥复选框禁用时栈溢出问题排查
解决Angular复选框互斥导致的栈溢出错误
问题原因
当前代码中两个复选框的valueChanges订阅形成了循环触发:勾选firstValue会禁用secondValue,而secondValue的禁用操作会触发自身的valueChanges,进而启用firstValue;firstValue的启用又会触发它的valueChanges,再次禁用secondValue。这种无限循环最终导致Maximum call stack size exceeded错误。
解决方案
在调用disable()或enable()方法时,传入{ emitEvent: false }选项,让控件状态变更时不触发valueChanges事件,打破循环。同时添加订阅清理逻辑,避免内存泄漏。
修改后的代码
组件代码
import { Subject, takeUntil } from 'rxjs'; // ... 其他必要导入 export class YourComponent implements OnInit, OnDestroy { private destroy$ = new Subject<void>(); settingsForm: FormGroup; constructor(private formBuilder: FormBuilder) {} ngOnInit(): void { this.initForm(); } private initForm(): void { this.settingsForm = this.formBuilder.group({ firstValue: [false], secondValue: [false] }); // 监听firstValue变化 this.settingsForm.get('firstValue').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe((value) => { const secondCtrl = this.settingsForm.get('secondValue'); if (value === true) { secondCtrl.disable({ emitEvent: false }); } else { // 仅当控件处于禁用状态时才启用,减少不必要操作 if (secondCtrl.disabled) { secondCtrl.enable({ emitEvent: false }); } } }); // 监听secondValue变化 this.settingsForm.get('secondValue').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe((value) => { const firstCtrl = this.settingsForm.get('firstValue'); if (value === true) { firstCtrl.disable({ emitEvent: false }); } else { if (firstCtrl.disabled) { firstCtrl.enable({ emitEvent: false }); } } }); } ngOnDestroy(): void { // 清理订阅,防止内存泄漏 this.destroy$.next(); this.destroy$.complete(); } }
HTML代码(无需修改)
<form name="settingsForm" novalidate [formGroup]="settingsForm"> <label class="switch"> <input formControlName="firstValue" type="checkbox" class="form-control"> <span class="slider round"></span> </label> <label class="switch"> <input formControlName="secondValue" type="checkbox" class="form-control"> <span class="slider round"></span> </label> </form>
补充说明
{ emitEvent: false }:禁用状态变更时的事件触发,彻底切断循环链条。takeUntil+destroy$:组件销毁时自动取消所有订阅,避免内存泄漏。
内容的提问来源于stack exchange,提问作者hello world
相关产品推荐
相关产品推荐

