触发Angular异步FormGroup验证

时间:2019-06-18 16:08:18

标签: angular angular-reactive-forms

背景

仅当该组及其所有子级的所有同步验证均有效时,才对FormGroup执行异步验证。

问题

我想在所有子项均有效之前在FormGroup上执行asyncValidator。

this.myForm = new FormGroup({
  country: [ null, [ Validators.required ] ],
  postalCode: [ null ],
  unrelatedField1: [ null ],
  unrelatedField2: [ Validators.min(123) ]
}, {
  validators: [ postalCodeFormat ],
  asyncValidators: [ postalCodeExists ]
})

我的自定义postalCodeExists验证器需要使用country和postalCode字段。它不在乎'unrelatedField2'的有效性。

有什么方法可以手动触发FormGroup的异步验证吗?

我的第一个想法

据我所知这是不可能的。

this.myForm.valueChanges.pipe(
  map(...etc),
  distinctUntilChanges(...etc)
).subscribe(() => {
  if (this.myForm.get('country').valid && this.myForm.get('postalCode').valid) {
    this.myForm.executeAsyncValidationPlease();
  }
});

我的第二个主意

this.myForm = new FormGroup({
  countryAndPostalCodeGroup: new FormGroup({
    country: [ null, [ Validators.required ] ],
    postalCode: [ null ],
  }, {
    validators: [ postalCodeFormat ],
    asyncValidators: [ postalCodeExists ]
  }),

  unrelatedField1: [ null ],
  unrelatedField2: [ Validators.min(123) ]
})

它将起作用。但是我不喜欢。我强烈希望为myForm,所有API和数据存储使用一种数据结构。进行this.myForm.setValue(dataFromApi)或相反的.getValue()变体真的很有帮助。

1 个答案:

答案 0 :(得分:1)

另一种方法是将异步验证器添加到每个FormControl中,并引用控件的父级以获得所需的其他值。本示例比较两个字符串(登录名/密码)以确保它们不匹配,即使extraField无效也可以执行。

matching-validator.ts(该计时器用于模拟)

import { FormControl, FormGroup } from '@angular/forms';
import { timer } from 'rxjs';
import { map } from 'rxjs/operators';

export const isMatchingValidator = (key: string) => {
  return (control: FormControl) => {
    return timer(500).pipe(
      map(() => {
        const group = control.parent as FormGroup;
        const key1 = group.get(key).value;
        const key2 = control.value;
        return key1 === key2 ?
          { matching: true } :
          null;
      })
    );
  };
}

表单创建:

    this.form = new FormGroup({
      login: new FormControl(
        null,
        Validators.required,
        isMatchingValidator('password')
      ),
      password: new FormControl(
        null,
        Validators.required,
        isMatchingValidator('login')
      ),
      extraField: new FormControl(
        null, Validators.required
      )
    });

如果您在任何字段中都存在错误,则可以在标记中显示该错误:

  <div *ngIf="form.get('login').hasError('matching') || form.get('password').hasError('matching')">
    ID and Password can't match.
  </div>

这是我从我派生的异步验证器示例中编辑的堆栈闪电: https://stackblitz.com/github/casetolleson/custom-async-validator