Angular 6反应式,同步跨场验证

时间:2018-09-21 09:37:33

标签: angular angular-reactive-forms angular-forms

@ angular / forms:6.1.7

我正在尝试创建一个自定义验证器,以检查2个 formControl 是否不一致。

在遵循official angular documentation时,将值输入2种形式之一时会出错:

Uncaught Error: Expected validator to return Promise or Observable.
    at toObservable (forms.js:596)
    at Array.map (<anonymous>)
    at FormControl.asyncValidator (forms.js:584)
    at FormControl.push../node_modules/@angular/forms/fesm5/forms.js.AbstractControl._runAsyncValidator (forms.js:2454)
    at FormControl.push../node_modules/@angular/forms/fesm5/forms.js.AbstractControl.updateValueAndValidity (forms.js:2427)
    at FormControl.push../node_modules/@angular/forms/fesm5/forms.js.FormControl.setValue (forms.js:2764)
    at updateControl (forms.js:1699)
    at DefaultValueAccessor.onChange (forms.js:1684)
    at DefaultValueAccessor.push../node_modules/@angular/forms/fesm5/forms.js.DefaultValueAccessor._handleInput (forms.js:741)
    at Object.eval [as handleEvent] (ChangePasswordComponent.html:13)

在这种情况下,Angular似乎尝试查找 asyncValidator ,而不是我期望的 sync 版本。

值得一提的是,我还试图返回一个Observable<ValidationErrors | null>,该错误给出了相同的错误输出。

验证者:

import { FormGroup, ValidationErrors, ValidatorFn } from '@angular/forms';

export const passwordMatchValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
  const password = control.get('password');
  const confirmPassword = control.get('confirmPassword');

  if (!password || !confirmPassword) {
    return null;
  }

  return password === confirmPassword ? null : { passwordMismatch: true };
};

实施:

  this.formGroup = this.formBuilder.group(
      {
        password: ['', Validators.required, Validators.minLength(6)],
        confirmPassword: ['', Validators.required, Validators.minLength(6)]
      },
      {
        validators: passwordMatchValidator
      }

问题

如何创建自定义同步跨字段验证器?

侧面的问题

是否可以将 formControl名称传递给函数,而不是对其进行硬编码?

更新:最终解决方案

import { FormGroup, ValidationErrors, ValidatorFn } from "@angular/forms";

export const matchValidator = (firstControlName: string, secondControlName: string): ValidatorFn => {
  return (control: FormGroup): ValidationErrors | null => {
      const firstControlValue = control.get(firstControlName).value;
      const secondControlValue =  control.get(secondControlName).value;
      if (!firstControlValue || !secondControlValue) {
          return null;
      }
      return firstControlValue === secondControlValue ? null : { mismatch: true };
  }
};

实施:

this.formGroup = this.formBuilder.group(
      {
        password: ['', [Validators.required, Validators.minLength(6)]],
        confirmPassword: ['', [Validators.required, Validators.minLength(6)]],
        currentPassword: ['', Validators.required]
      },
      {
        validator: matchValidator('password', 'confirmPassword')
      }

1 个答案:

答案 0 :(得分:2)

根据文档,应将QProcess *pro = new QProcess; QString s = "\"C:\Users\xyz\Desktop\Example.exe"; pro ->start(s); 中的validator函数的extra属性传递到group参数中。参见the docs。第二个问题是,在创建表单控件时应将数组作为第二个参数传递,并直接使用FormBuilder设置验证器:

formBuilder

因为当前password: ['', [Validators.required, Validators.minLength(6)]]验证器被视为minLength,因为它是第三个参数。

侧面问题

您可以创建一个验证器工厂函数,该函数为您创建验证器并采用2个控件:

asyncValidator

和用法:

export const passwordMatchValidator = (passwordControl: AbstractControl, confirmPasswordControl: AbstractControl): ValidatorFn => { return (control: FormGroup): ValidationErrors | null => { const password = passwordControl.value; const confirmPassword = confirmPasswordControl.value; if (!password || !confirmPassword) { return null; } return password === confirmPassword ? null : { passwordMismatch: true }; } }; ;

或工厂函数可以只使用字符串参数而不是控件,然后提取表单控件本身。