Angular 两个字段之间的条件要求验证器
Angular conditional required validator between two fields
我需要对表单进行验证以使用户至少填写两个字段之一
我试过这样的自定义验证器:
export function conditionalValidator(
predicate: () => boolean,
validator: ValidatorFn
): ValidatorFn {
return formControl => {
if (!formControl.parent) {
return null;
}
let error = null;
if (predicate()) {
error = validator(formControl);
}
return error;
};
}
然后在我的表单中
this.myForm= this.fb.group({
field1: ['', conditionalValidator(() => !(this.myForm.get('field1').value || this.myForm.get('field2').value), Validators.required)],
field2: ['', conditionalValidator(() => !(this.myForm.get('field1').value || this.myForm.get('field2').value), Validators.required)],
});
this.myForm.get('field1').valueChanges.subscribe(_ => {
this.myForm.updateValueAndValidity();
});
this.myForm.get('field2').valueChanges.subscribe(_ => {
this.myForm.updateValueAndValidity();
});
但是不知道为什么不行
我也尝试过更“手工”的方式 (stackblitz link here),但也没有成功
这就是组验证器(而非字段验证器)的用途。
this.myForm= this.fb.group({
field1: ['', Validators.required],
field2: ['', Validators.required],
}, {
validators: [/* put your multi-field validator here */],
}});
正如 mbojko 所说,您可以在整个 formGroup 上创建自定义验证器。这使得验证器在表单中的每个更改都被执行。如果只有这两个字段就是最优解。
但是您也可以在一个字段上使用自定义验证器,问题是只有在更改表单控件时才执行验证器,但首先我们将看到验证器
export function conditionalValidator(field:string): ValidatorFn {
return (formControl) => {
if (!formControl.parent) {
return null;
}
return formControl.value || formControl.parent.get(field).value?
null: {error:"this field or "+field+" is required"}
};
}
然后你使用 like
this.myForm = this.fb.group({
myField: ["",conditionalValidator("otherField")],
otherField: ["",conditionalValidator("myField")],
});
好吧,正如我所说,当我们将自定义表单控件制作成一个中继到另一个控件的控件时,问题是我们需要检查另一个控件何时发生更改。您订阅控件的 valueChanges。您可以使用 merge
rxjs 运算符来获得唯一的订阅
merge(this.myForm.get("otherField").valueChanges,
this.myForm.get("myField").valueChanges)
.subscribe(_ => {
this.myForm.get("otherField").updateValueAndValidity({emitEvent:false});
this.myForm.get("myField").updateValueAndValidity({emitEvent:false})
});
Update 好吧,我们知道每次我们的控件更改时都会执行验证器,所以为什么不考虑这一点并在此函数中对其他字段进行 updateValueAndValidity ?
好吧,只有当 is 有效且有错误或无效且没有错误时我们才需要执行,否则我们会得到一个递归错误
export function conditionalValidator(field: string): ValidatorFn {
return formControl => {
if (!formControl.parent) {
return null;
}
const otherControl = formControl.parent.get(field);
const error =
formControl.value || otherControl.value
? null
: { error: "this field or " + field + " is required" };
if ((error && otherControl.valid) || (!error && otherControl.invalid)) {
setTimeout(() => {
otherControl.updateValueAndValidity({ emitEvent: false });
});
}
return error;
};
}
所以,我们不需要订阅
看到一个new stackblitz
我需要对表单进行验证以使用户至少填写两个字段之一
我试过这样的自定义验证器:
export function conditionalValidator(
predicate: () => boolean,
validator: ValidatorFn
): ValidatorFn {
return formControl => {
if (!formControl.parent) {
return null;
}
let error = null;
if (predicate()) {
error = validator(formControl);
}
return error;
};
}
然后在我的表单中
this.myForm= this.fb.group({
field1: ['', conditionalValidator(() => !(this.myForm.get('field1').value || this.myForm.get('field2').value), Validators.required)],
field2: ['', conditionalValidator(() => !(this.myForm.get('field1').value || this.myForm.get('field2').value), Validators.required)],
});
this.myForm.get('field1').valueChanges.subscribe(_ => {
this.myForm.updateValueAndValidity();
});
this.myForm.get('field2').valueChanges.subscribe(_ => {
this.myForm.updateValueAndValidity();
});
但是不知道为什么不行
我也尝试过更“手工”的方式 (stackblitz link here),但也没有成功
这就是组验证器(而非字段验证器)的用途。
this.myForm= this.fb.group({
field1: ['', Validators.required],
field2: ['', Validators.required],
}, {
validators: [/* put your multi-field validator here */],
}});
正如 mbojko 所说,您可以在整个 formGroup 上创建自定义验证器。这使得验证器在表单中的每个更改都被执行。如果只有这两个字段就是最优解。
但是您也可以在一个字段上使用自定义验证器,问题是只有在更改表单控件时才执行验证器,但首先我们将看到验证器
export function conditionalValidator(field:string): ValidatorFn {
return (formControl) => {
if (!formControl.parent) {
return null;
}
return formControl.value || formControl.parent.get(field).value?
null: {error:"this field or "+field+" is required"}
};
}
然后你使用 like
this.myForm = this.fb.group({
myField: ["",conditionalValidator("otherField")],
otherField: ["",conditionalValidator("myField")],
});
好吧,正如我所说,当我们将自定义表单控件制作成一个中继到另一个控件的控件时,问题是我们需要检查另一个控件何时发生更改。您订阅控件的 valueChanges。您可以使用 merge
rxjs 运算符来获得唯一的订阅
merge(this.myForm.get("otherField").valueChanges,
this.myForm.get("myField").valueChanges)
.subscribe(_ => {
this.myForm.get("otherField").updateValueAndValidity({emitEvent:false});
this.myForm.get("myField").updateValueAndValidity({emitEvent:false})
});
Update 好吧,我们知道每次我们的控件更改时都会执行验证器,所以为什么不考虑这一点并在此函数中对其他字段进行 updateValueAndValidity ?
好吧,只有当 is 有效且有错误或无效且没有错误时我们才需要执行,否则我们会得到一个递归错误
export function conditionalValidator(field: string): ValidatorFn {
return formControl => {
if (!formControl.parent) {
return null;
}
const otherControl = formControl.parent.get(field);
const error =
formControl.value || otherControl.value
? null
: { error: "this field or " + field + " is required" };
if ((error && otherControl.valid) || (!error && otherControl.invalid)) {
setTimeout(() => {
otherControl.updateValueAndValidity({ emitEvent: false });
});
}
return error;
};
}
所以,我们不需要订阅
看到一个new stackblitz