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

Angular切换按钮控制的复选框勾选状态丢失问题求助

问题解决:切换显示隐藏后复选框勾选状态丢失

问题重现

  • 页面加载:仅当切换按钮为“oui”时复选框可见,流程正常
  • 勾选“invalidité”复选框,触发输入元素显示,流程正常
  • 切换按钮至“no”,所有复选框隐藏,流程正常
  • 再次切回“oui”时,复选框的勾选标记消失,出现异常

问题根源分析

  1. 子组件未实现表单双向同步:复选框组件的ControlValueAccessor核心方法全部为空实现,导致视图勾选状态无法同步到FormControl模型,同时模型值也无法反向更新视图状态。
  2. 父组件未同步表单控件值:父组件的isInvalidityCheckboxChecked方法仅更新了本地变量isInvalidityChecked,但没有修改对应FormControl的实际值,导致表单模型始终保留初始的false。
  3. 组件销毁重建重置状态:如果使用*ngIf控制复选框显示隐藏,组件会被销毁再重建,此时会从表单模型读取初始值,而非之前的勾选状态。

修复方案

1. 完善复选框子组件的表单绑定逻辑

子组件HTML修改

为复选框input绑定FormControl,确保视图与模型联动:

<div class="c-form__tooltip align-items-center u-margin-bottom& md u-margin-bottom sm@tablet">
  <div class="c-input-checkbox-list u-margin-bottom-sm" [ngClass]="{'error' : control.invalid && control.touched}">
    <input 
      type="checkbox" 
      name="{{ formControlName }}" 
      id="{{ formControlName }}" 
      [formControl]="control"
      (change)="checkValue($event)"
    >
    <label for="{{ formControlName }}">{{ page + '.' + formControlName | translate }}</label>
  </div>
  <div class="c-tooltip">
    <i class="c-tooltip__icon icon-question-circle-5"></i>
    <span class="c-tooltip__text" style="width:450px">
      tooltip test temporaire
    </span>
  </div>
</div>

子组件TS实现完整的ControlValueAccessor

补全表单同步的核心方法:

export class CheckBoxComponent implements ControlValueAccessor {

  @Input() public formControl: FormControl;
  @Input() public formControlName: string;
  @Input() public page: string;
  @Input() public index: number = 0;

  @Output() public onChecked: EventEmitter<boolean> = new EventEmitter<boolean>();

  @ViewChild(FormControlDirective, {static: true})
  public formControlDirective: FormControlDirective;

  onChange: (value: boolean) => void = () => {};
  onTouched: () => void = () => {};

  get control(): FormControl {
    return this.formControl || this.controlContainer.control.get(this.formControlName) as FormControl;
  }

  constructor(private controlContainer: ControlContainer) {
  }

  public registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  public registerOnChange(fn: (value: boolean) => void): void {
    this.onChange = fn;
  }

  public writeValue(value: boolean): void {
    this.control.setValue(value);
  }

  public setDisabledState(isDisabled: boolean): void {
    isDisabled ? this.control.disable() : this.control.enable();
  }

  public checkValue(event: Event): void {
    const isChecked = (event.target as HTMLInputElement).checked;
    this.onChange(isChecked);
    this.onChecked.emit(isChecked);
    this.onTouched();
  }
}

2. 修复父组件的表单值同步逻辑

修改isInvalidityCheckboxChecked方法,确保勾选状态同步到FormControl:

public isInvalidityCheckboxChecked(isChecked: Event): void {
  const checked = (isChecked.target as HTMLInputElement).checked;
  this.isInvalidityChecked = checked;
  // 同步更新表单控件的值
  this.form.controls.invalidityCheckbox.setValue(checked);
  
  if (checked) {
    Solutions03CurrentProtectionComponent.addControlsInvalidity(this.form.controls.invalidity as FormGroup);
  } else {
    Solutions03CurrentProtectionComponent.removeControlsInvalidity(this.form.controls.invalidity as FormGroup);
  }
}

3. 避免组件销毁重置状态(可选)

如果之前使用*ngIf控制显示,改为[hidden](仅隐藏DOM,不销毁组件):

<!-- 替换原*ngIf写法 -->
<amp-check-box [hidden]="!isPensionContract" 
  [formControl]="form.controls.invalidityCheckbox"
  [formControlName]="'invalidityCheckbox'"
  [page]="page"
  (onChecked)="isInvalidityCheckboxChecked($event)">
</amp-check-box>

验证步骤

  1. 切换按钮至“oui”,勾选复选框,确认form.controls.invalidityCheckbox的值变为true
  2. 切换按钮至“no”,复选框隐藏
  3. 切回“oui”,复选框的勾选状态应正常保留,表单控件值仍为true

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 03:54:15