由于没有优雅的解决方案,我咬紧牙关编写自己的RequiredIf 验证器。
它做了两件事:
- 缓存应用它的控件的原始验证器。如果不再需要某个属性,它将恢复原始验证器(同时删除所需的验证器)。
- 它在属性上添加了 valueChange 侦听器,验证取决于。如果某个属性变得需要或不再需要,它将验证控件以立即显示新的验证结果。
这是我的验证器代码(就像我目前使用的一样,没有时间优化它)。
import { FormGroup, ValidationErrors, Validators } from '@angular/forms';
import { Subscription } from 'rxjs';
export class ValidationSubscriptionCache {
static observedPropertyCombinations = new Array<string>();
static subscriptions = new Array<Subscription>();
static unsubscribeAll() {
for (let subscription of ValidationSubscriptionCache.subscriptions) {
subscription.unsubscribe();
}
}
}
export function CombineProperties(property: string, otherProperty: string) {
return `${ property }.${ otherProperty }`;
}
export class ValidatorCache {
static cache = new Array<ValidatorsOfProperty>();
static currentlyRequiredProperties = new Array<string>();
static isCurrentlyRequired(property: string) {
return ValidatorCache.currentlyRequiredProperties.indexOf(property) > -1;
}
static removeFromCurrentlyRequiredProperties(property: string) {
const index = ValidatorCache.currentlyRequiredProperties.indexOf(property, 0);
if (index > -1) {
ValidatorCache.currentlyRequiredProperties.splice(index, 1);
}
}
static isInCache(property: string) {
const found = this.cache.find(x => x.property === property);
if (found) {
return true;
}
return false;
}
static addToCache(property: string, validators: any) {
const toAdd = new ValidatorsOfProperty();
toAdd.property = property;
toAdd.validators = validators;
ValidatorCache.cache.push(toAdd);
}
static popFromCache(property: string): ValidatorsOfProperty {
const item = ValidatorCache.cache.find(x => x.property === property);
const index = ValidatorCache.cache.indexOf(item, 0);
ValidatorCache.cache.splice(index, 1);
return item;
}
}
export class ValidatorsOfProperty {
property: string;
validators: any;
}
export function ValidateRequiredIf(property: string, otherProperty: string, valueThatMakesRequired) {
return (formGroup: FormGroup): ValidationErrors | null => {
const propertyCombination = CombineProperties(property, otherProperty);
const otherValue = formGroup.get(otherProperty).value;
//register changes of other property and refresh validation if it changes
if (ValidationSubscriptionCache.observedPropertyCombinations.indexOf(propertyCombination) < 0) {
ValidationSubscriptionCache.observedPropertyCombinations.push(propertyCombination);
const valueChangeSubscription =
formGroup.get(otherProperty).valueChanges
.subscribe(() => {
formGroup.get(property).markAsTouched();
formGroup.get(property).updateValueAndValidity();
});
ValidationSubscriptionCache.subscriptions.push(valueChangeSubscription);
}
//set or remove the required validator based on the depending property
const isRequired =
otherValue !== null &&
otherValue !== undefined &&
otherValue.toString() === valueThatMakesRequired.toString();
if (isRequired && !ValidatorCache.isCurrentlyRequired(property)) {
ValidatorCache.currentlyRequiredProperties.push(property);
ValidatorCache.addToCache(property, formGroup.get(property).validator);
if (formGroup.get(property).validator) {
formGroup.get(property).setValidators([ formGroup.get(property).validator, Validators.required ]);
} else {
formGroup.get(property).setValidators(Validators.required);
}
}
if (!isRequired && ValidatorCache.isCurrentlyRequired(property)) {
ValidatorCache.removeFromCurrentlyRequiredProperties(property);
formGroup.get(property).setValidators(ValidatorCache.popFromCache(property).validators);
}
return null;
};
}
这是表格上的应用程序:
this.myForm.setValidators(
[
//city is required if the country is switzerland
ValidateRequiredIf('city', 'nationality', 'switzerland'),
//[add more]
]);
此外,您必须调用持有表单的组件ValidationSubscriptionCache.unsubscribeAll();
。ngOnDestroy()
干杯,迈克