我正在使用Angular反应形式。在我的场景中,验证器会动态添加到我的控件中。
此操作如下:
const myControl = myFormGroup.get('myControl');
if (myControl.validator) {
myControl.setValidators([ myControl.validator, Validators.required ]); //preserve existing validators
} else {
myControl.setValidators([ Validators.required ]);
}
这很好用。
问题
我需要一种在保留其他验证器的同时也删除其他验证器的方法。
[myControl.validators
仅返回一个函数,但不返回一个验证器数组,这使得无法选择一个要删除的函数而保留另一个函数。
我知道有一些变通办法,例如在其他地方跟踪现有的验证器等。但是我的问题是:可以直接在AbstractControl
上实现吗?
以下有关Github的问题讨论了这个问题:https://github.com/angular/angular/issues/13461
那里提供的解决方案似乎对我不起作用,因为我不仅要处理所需的验证器,而且还要处理许多自定义验证器。
感谢您对此的任何提示或解决方案!
干杯,迈克
由于对此没有完美的解决方案,所以我咬牙切齿地编写了自己的RequiredIf验证器。
它有两件事:
这是我的验证器代码(就像我目前使用的那样,没有时间对其进行优化)。
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()
。
干杯,迈克