【问题标题】:Angular 6 reactive forms, synchronous cross field validationAngular 6 反应形式,同步跨字段验证
【发布时间】:2018-09-21 09:37:33
【问题描述】:

@angular/forms:6.1.7

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

当关注official angular documentation 时,将值输入到以下两种形式之一时出现错误:

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&lt;ValidationErrors | null&gt;,它给了我相同的错误输出。

验证器:

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')
      }

【问题讨论】:

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


    【解决方案1】:

    根据文档,您应该将validator 属性传递给extra 参数,用于group 中的group 函数FormBuilder。见the docs。第二个问题是您应该在创建表单控件时将数组作为第二个参数传递,并且您直接使用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'));

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

    【讨论】:

    • 非常感谢!
    猜你喜欢
    • 2022-11-03
    • 2019-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-21
    • 1970-01-01
    • 2019-08-17
    相关资源
    最近更新 更多