Angular 6 种反应形式,同步交叉字段验证
Angular 6 reactive forms, synchronous cross field validation
@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 版本期待。
值得一提的是,我也曾尝试 return 一个 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')
}
根据文档,对于 FormBuilder
中的 group
函数,您应该将 validator
属性 传递给 extra
参数。参见 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'))
;
或者工厂函数可以只接受字符串参数而不是控件并提取表单控件本身。
@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 版本期待。
值得一提的是,我也曾尝试 return 一个 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')
}
根据文档,对于 FormBuilder
中的 group
函数,您应该将 validator
属性 传递给 extra
参数。参见 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'))
;
或者工厂函数可以只接受字符串参数而不是控件并提取表单控件本身。