【问题标题】:Angular Reactive Form Validation : Expression has changed after it was checkedAngular Reactive Form Validation:表达式在检查后发生了变化
【发布时间】:2021-04-22 14:52:48
【问题描述】:

我有一个带有自定义 FormControl 的响应式表单。第一次加载屏幕,虽然自定义控件是必填字段,但我的Form是有效的。

如果我触发了任何更改,例如通过勾选表单中的复选框,那么在我向自定义控件填充值之前,表单将被标记为无效。

如果我重置自定义控件的值,则表单会再次被标记为无效,并且从那时起它会按预期工作。

所以只有当表单第一次在屏幕上加载时才会出现问题。

我在控制台中注意到以下异常:

这个错误是由我的自定义控件的验证器触发的,因为如果我评论它,错误就会消失。

下面是我的自定义控件的代码。我是不是做错了什么?

import { Component, forwardRef, Input, OnInit, Output } from '@angular/core';
import { ControlValueAccessor, FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
  selector: 'app-multiple-checkbox',
  templateUrl: './multiple-checkbox.component.html',
  styleUrls: ['./multiple-checkbox.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => MultipleCheckboxComponent),
      multi: true
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => MultipleCheckboxComponent),
      multi: true
    }]
})
export class MultipleCheckboxComponent implements OnInit, ControlValueAccessor {

  value = [];
  disabled = false;

  @Input() public options: { key, value }[];

  onTouched: any;
  onChange: any;


  constructor() { }

  validate({ value }: FormControl) {
   
    const isNotValid = this.value.length === 0;
    return isNotValid && {
      invalid: true
    };
  }

  ngOnInit(): void { }

  evaluate(event, key): void {
    if (event.target.checked) {
      this.value.push(key);
    } else {
      this.value.splice(this.value.findIndex(i => key === i), 1);
    }

    this.onChange(this.value);
    this.onTouched();
  }

  isChecked(key): boolean {
    return this.value.findIndex(e => e === key) > -1;
  }

  writeValue(value: any): void {
    this.value = value;
  }
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

}

[编辑] 添加自定义控件在其父窗体中添加到屏幕的方式:

<div [formGroup]="form">
 <div *ngIf="control.visible">

    <div [ngSwitch]="control.controlType">

        <div *ngSwitchCase="'checkbox'">
            <label [attr.for]="control.key">{{control.label}}</label>

            <input [formControlName]="control.key" [id]="control.key" type="checkbox"
                (change)="evaluate(control.key)">
        </div>

<!--  THIS IS MY CUSTOM CONTROL -->

        <app-multiple-checkbox *ngSwitchCase="'multipleCheckbox'" [formControlName]="control.key"
            [options]="control.options" (change)="evaluate(control.key)">
        </app-multiple-checkbox>
    </div>
</div>

[编辑]

根据下面的评论,错误是由我表单中的这一行触发的:

<button type="submit" color="accent" (click)="save()" 
 [disabled]="catalogForm.invalid">Submit</button>

【问题讨论】:

  • 你能创建 stackblitz 吗?
  • 您能否展示一下您是如何使用此自定义组件的,例如你如何将它嵌入到你的模板中? validate 方法是如何被调用的?您是否将其用作使用此组件的FormControlValidatorFn
  • @Eddi 我编辑了缺少信息的问题。我刚刚实现了Validator 接口,所以不需要做任何其他调用。同样,除了第一次(在表单变脏之前)之外,工作正常
  • @Sam 这对我来说看起来不错。您提供的错误消息说明了第 11 行 catalog.component.html 中的 [disabled] 属性。所以基本上您在那里使用的任何表达式都“过早地”改变了。在大多数情况下,我知道当您更改 ngAfterViewInit 中的表达式值时会发生这种情况。
  • 实际上对于响应式表单更常见的方式是订阅 ts 文件中表单的 valueChanges 而不是模板 (change) 处理程序。我相信它可以解决您的问题

标签: angular angular-reactive-forms


【解决方案1】:

检查后表达式发生了变化

上述错误仅在开发模式下出现。 在生产中这个错误不存在。

在开发模式下消除这个错误

import ChangeDetectorRef from  @angular/core

constructor(private changeDecRef:ChangeDetectorRef) {}

然后

    if (event.target.checked) {
      this.value.push(key);
    } else {
      this.value.splice(this.value.findIndex(i => key === i), 1);
    }

    this.onChange(this.value);
    this.onTouched();

    /// ADD THIS FUNCTION ///
    this.changeDecRef.detectChanges();
  }```

【讨论】:

  • 但我不禁想到这与我面临的验证问题有关。这无法解释为什么表单在不应该有效的情况下有效。
  • 它表明在生产模式下可能会出错。所以你不能忽视它
  • 如果我添加你的代码,错误仍然存​​在,我的问题仍然存在。
  • @sam 你必须在 catalouge.component.ts 文件中添加它..
  • 我也试过了,但没有任何效果了。 FormControls 不再添加到表单中。
猜你喜欢
  • 2018-11-17
  • 2017-12-27
  • 2019-01-05
  • 1970-01-01
  • 1970-01-01
  • 2017-01-20
  • 1970-01-01
相关资源
最近更新 更多