我应该如何有条件地要求表单域?我制作了一个自定义验证器,但我传递给自定义验证器的条件变量是静态的,并保持其初始值。我的自定义验证器应该是什么样子才能获得更新的条件值?也许有一种方法可以使用 Validators.required
而不是自定义验证器来做到这一点?
private foo: boolean = false;
private bar: boolean = true;
constructor(private _fb: FormBuilder) {
function conditionalRequired(...conditions: boolean[]) {
return (control: Control): { [s: string]: boolean } => {
let required: boolean = true;
for (var i = 0; i < conditions.length; i++) {
if (conditions[i] === false) {
required = false;
}
}
if (required && !control.value) {
return { required: true }
}
}
}
this.applyForm = _fb.group({
'firstName': ['', Validators.compose([
conditionalRequired(this.foo, !this.bar)
])],
...
});
}
更新(2016 年 5 月 17 日)
发布这篇文章已经有很长时间了,但我想引用 上可用的
类,适用于尝试创建此功能的任何人。 ( docs ) 虽然可能有像上面这样的条件验证器的用例,但我发现包含和排除控件、控件组和控件数组是处理此问题的好方法。只需在您想要的控件上设置 .include()
和 .exclude()
方法ControlGrouprequired
验证器,然后根据需要包含/排除它。希望这对某人有帮助!
最佳答案
我想要一个更通用的版本,所以我为它编写了一个额外的验证器,可以与其他验证器组合在一起。我仍然刚刚开始研究表单模块,所以不要指望这是有史以来最有效的代码或在边缘情况下工作,但这是一个好的开始。它适用于正常用例,并且可以作为其他用例的良好起点。
为 rc.4 和新的表单模块制作,revalidateOnChanges 部分可能很糟糕(不确定导致此行为的最佳方法),使用风险自负! :)
如何使用它
验证器有两个参数,一个是给定 formGroup 的条件函数,如果要应用验证则预期返回 true,否则返回 false,以及一个验证器(可能是一个组合)。它会在 formGroup 更新时重新验证该字段,目前它只能检查同一 formGroup 内的内容,但这应该很容易修复。
this.formBuilder.group({
vehicleType: ['', Validators.required],
licencePlate: [
'',
ExtraValidators.conditional(
group => group.controls.vehicleType.value === 'car',
Validators.compose([
Validators.required,
Validators.minLength(6)
])
),
]
});
在此示例中,您有两个字段,vehicleType 和 licencePlate。如果 vehicleType 是“car”,条件语句将应用组合的验证器(必需和 minLength)。
您可以使用 compose 应用多个不同的条件,这些条件可能会或可能不会同时应用。这是一个稍微复杂一点的例子:
this.formBuilder.group({
country: ['', Validators.required],
vehicleType: ['', Validators.required],
licencePlate: [
'',
Validators.compose([
ExtraValidators.conditional(
group => group.controls.vehicleType.value === 'car',
Validators.required
),
ExtraValidators.conditional(
group => group.controls.country.value === 'sweden',
Validators.minLength(6)
),
])
]
});
在这种情况下,如果 type 是“car”,我们应用 required,如果 country 是“Sweden”,我们应用 minLength。如果只有一个条件适用,则验证将适用,如果两个条件都适用,则两个验证都适用。
验证器本身
请注意,对象比较只是一个简单的蛮力,因为我们正在处理小对象,如果您使用 Ramda 或其他东西,您可以减少很多代码。
export class ExtraValidators {
static conditional(conditional, validator) {
return function(control) {
revalidateOnChanges(control);
if (control && control._parent) {
if (conditional(control._parent)) {
return validator(control);
}
}
};
}
}
function revalidateOnChanges(control): void {
if (control && control._parent && !control._revalidateOnChanges) {
control._revalidateOnChanges = true;
control._parent
.valueChanges
.distinctUntilChanged((a, b) => {
// These will always be plain objects coming from the form, do a simple comparison
if(a && !b || !a && b) {
return false;
} else if (a && b && Object.keys(a).length !== Object.keys(b).length) {
return false;
} else if (a && b) {
for (let i in a) {
if(a[i] !== b[i]) {
return false;
}
}
}
return true;
})
.subscribe(() => {
control.updateValueAndValidity();
});
control.updateValueAndValidity();
}
return;
}
注意:记得导入运算符:
导入 'rxjs/add/operator/distinctUntilChanged';
关于Angular 2条件Validators.required?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36118721/