首页 > 解决方案 > Angular 6 反应形式,同步跨字段验证

问题描述

@角/形式:6.1.7

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

遵循官方角度文档时,在将值输入以下两种形式之一时出现错误:

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 ,而不是我期望的同步版本。

值得一提的是,我也尝试返回一个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')
      }

标签: angularangular-reactive-formsangular-forms

解决方案


根据文档,您应该将validator属性传递给extra参数中的group函数FormBuilder。请参阅文档。第二个问题是,您应该在创建表单控件时将数组作为第二个参数传递,并直接使用以下命令设置验证器formBuilder

password: ['', [Validators.required, Validators.minLength(6)]]

因为目前minLength验证器被视为asyncValidator第三个参数。

附带问题

您可以创建一个验证器工厂函数,为您创建验证器并进行 2 个控制:

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 }; } };

和用法:

passwordMatchValidator(this.formGroup.get('password'),this.formGroup.get('confirmPassword'));

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


推荐阅读