39

在我的 Angular 4 应用程序中,我有一个带有多个控件的表单。

在某些时候我需要强制更新它们的有效性,所以我正在做:

this.form.get('control1').updateValueAndValidity();
this.form.get('control2').updateValueAndValidity();
this.form.get('control3').updateValueAndValidity();
// and so on....

接着:

this.form.updateValueAndValidity();

这很好用。

但是我想知道是否有更好的方法来完成同样的事情,只需在父表单上调用一个方法。

根据其文档,该updateValueAndValidity()方法:

默认情况下,它还会更新其祖先的值和有效性。

但就我而言,我需要更新其后代的价值和有效性。所以我可以摆脱很多行代码。

4

6 回答 6

16

FormGroup | FormArray在嵌套级别控件处更新时遇到了同样的情况。

看看这个(为我工作):

/**
 * Re-calculates the value and validation status of the entire controls tree.
 */
function updateTreeValidity(group: FormGroup | FormArray): void {
  Object.keys(group.controls).forEach((key: string) => {
    const abstractControl = group.controls[key];

    if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) {
      updateTreeValidity(abstractControl);
    } else {
      abstractControl.updateValueAndValidity();
    }
  });
}
于 2020-01-07T15:02:52.597 回答
13

目前无法使用 AbstractControl 本身更新 AbstractControl (FormGroup, ...) 的后代。也许在未来的版本中它是可能的。

https://github.com/angular/angular/issues/6170

https://github.com/angular/angular/issues/22166

更新:拉取请求已经打开 https://github.com/angular/angular/pull/19829

于 2018-02-13T10:24:52.477 回答
9

通过递归控件并手动触发更新,我解决了与您的问题类似的问题。可能这不是最佳解决方案:

private triggerValidation(control: AbstractControl) {
    if (control instanceof FormGroup) {
        const group = (control as FormGroup);

        for (const field in group.controls) {
            const c = group.controls[field];

            this.triggerValidation(c);
        }
    }
    else if (control instanceof FormArray) {
        const group = (control as FormArray);

        for (const field in group.controls) {
            const c = group.controls[field];

            this.triggerValidation(c);
        }
    }

    control.updateValueAndValidity({ onlySelf: false });
}
于 2019-02-25T15:06:11.920 回答
2
validateFormFields(fields) {
    try {
      Object.entries(fields.controls).forEach((control: any) => {
        if (typeof control[0] == 'Array' 
        ) {
          this.validateFormFields(control[1]);
        } else {
          if (control[1].controls) {
            Object.entries(control[1].controls).forEach((c: any) => {
              c[1].touched = true;
            });
          } else {
            control[1].touched = true;
          }

        }
      });
    } catch (e) {
      console.log(e);
    }
  }
于 2019-08-23T13:19:33.520 回答
1

如果您需要触发对控件及其后代的验证,则可以updateTreeValidity在它不是公共 API 的一部分时调用一种解决方法:

(<any>form)._updateTreeValidity({ emitEvent: false });

此处正在跟踪该问题:https ://github.com/angular/angular/issues/6170

于 2021-09-17T21:24:21.120 回答
1

我遇到了同样的问题,其中一个问题是监听valueChangesobservable 并触发updateValueAndValidity运行我的验证器导致了一个无限循环,所以为了解决(而且有点 hacky ?)我创建了组件变量validityCycleFired并初始化为 false,我切换它可以防止失控循环:

const fireValidityCheck = () => {
     if (this.validityCycleFired) return;
     this.validityCycleFired = true;
     this.passwordForm.get('old_password').updateValueAndValidity();
     this.passwordForm.get('new_password').updateValueAndValidity();
     this.passwordForm.get('confirm_new_password').updateValueAndValidity();
     setTimeout(() => this.validityCycleFired = false, 15);
     return;
};
this.passwordForm.valueChanges.subscribe(fireValidityCheck);
于 2020-07-23T20:58:12.120 回答