Angular2 形式:具有相关字段的验证器
Angular2 forms : validator with interrelated fields
给定一个表格,可以在其中输入城市名称或其纬度和经度。该表单将验证是否填写了城市名称,或者是否同时填写了纬度和经度。纬度和经度(如果已填写)必须是数字。
我可以使用这三个字段创建一个FormGroup
并执行一个自定义验证器......
function fatValidator(group: FormGroup) {
// if cityName is present : is valid
// else if lat and lng are numbers : is valid
// else : is not valid
}
builder.group({
cityName: [''],
lat: [''],
lng: ['']
},
{
validators: fatValidator
});
。但我想利用验证器的组合(例如,在一个验证器中测试纬度和经度是否为字段级别的有效数字,并在另一个验证器中测试组级别的相互关系)。
我已经测试了几个选项,但我坚持这样一个事实,即如果组的所有字段都有效,则该组是有效的。以下构造似乎不是解决问题的正确方法:
function isNumber(control: FormControl) { ... }
function areAllFilled(group: FormGroup) { ... }
function oneIsFilledAtLeast(group: FormGroup) { ... }
builder.group({
cityName: [''],
localisation: builder.group({
lat: ['', Validators.compose([Validators.minLength(1), isNumber])],
lng: ['', Validators.compose([Validators.minLength(1), isNumber])]
},
{
validators: areAllFilled
})
},
{
validators: oneIsFilledAtLeast
});
你会如何使用 Angular2 做到这一点,甚至可能吗?
编辑
下面是如何实现fatValidator
的示例。如您所见,它不可重用,并且比组合验证器更难测试:
function fatValidator (group: FormGroup) {
const coordinatesValidatorFunc = Validators.compose([
Validators.required,
CustomValidators.isNumber
]);
const cityNameControl = group.controls.cityName;
const latControl = group.controls.lat;
const lngControl = group.controls.lng;
const cityNameValidationResult = Validators.required(cityNameControl);
const latValidationResult = coordinatesValidatorFunc(latControl);
const lngValidationResult = coordinatesValidatorFunc(lngControl);
const isCityNameValid = !cityNameValidationResult;
const isLatValid = !latValidationResult;
const isLngValid = !lngValidationResult;
if (isCityNameValid) {
return null;
}
if (isLatValid && isLngValid) {
return null;
}
if (!isCityNameValid && !isLatValid && !isLngValid) {
return { cityNameOrCoordinatesRequired: true, latAndLngMustBeNumbers: true };
}
return Object.assign({},
{ cityName: cityNameValidationResult },
{ lat: latValidationResult },
{ lng: lngValidationResult }
);
}
使用Angular的最终版本或新版本,我编写了一个可重用的方法,将条件必需或其他验证添加到给定的控件集。
export class CustomValidators {
static controlsHaveValueCheck(controlKeys: Array<string>, formGroup: FormGroup): Array<boolean> {
return controlKeys.map((item) => {
// reset any errors already set (ON ALL GIVEN KEYS).
formGroup.controls[item].setErrors(null);
// Checks for empty string and empty array.
let hasValue = (formGroup.controls[item].value instanceof Array) ? formGroup.controls[item].value.length > 0 :
!(formGroup.controls[item].value === "");
return (hasValue) ? false : true;
});
}
static conditionalAnyRequired(controlKeys: Array<string>): ValidatorFn {
return (control: FormControl): {[key: string]: any} => {
let formGroup = control.root;
if (formGroup instanceof FormGroup) {
// Only check if all FormControls are siblings(& present on the nearest FormGroup)
if (controlKeys.every((item) => {
return formGroup.contains(item);
})) {
let result = CustomValidators.controlsHaveValueCheck(controlKeys, formGroup);
// If any item is valid return null, if all are invalid return required error.
return (result.some((item) => {
return item === false;
})) ? null : {required: true};
}
}
return null;
}
}
}
这可以像这样在代码中使用:
this.form = new FormGroup({
'cityName': new FormControl('',
CustomValidators.conditionalAnyRequired(['cityName', 'lat', 'lng'])),
'lat': new FormControl('',
Validators.compose([Validators.minLength(1),
CustomValidators.conditionalAnyRequired(['cityName', 'lat', 'lng']))),
'lng': new FormControl('',
Validators.compose([Validators.minLength(1),
CustomValidators.conditionalAnyRequired(['cityName', 'lat', 'lng'])))
})
这将使任何'city'
、'lat'
或'lng'
成为必需的。
此外,如果您希望需要'city'
或'lat'
和'lng'
,则可以包含额外的验证器,如下所示:
static conditionalOnRequired(conditionalControlKey: string, controlKeys: Array<string>): ValidatorFn {
return (control: FormControl): {[key: string]: any} => {
let formGroup = control.root;
if (formGroup instanceof FormGroup) {
if (controlKeys.every((item) => {
return formGroup.contains(item);
}) && formGroup.contains(conditionalControlKey)) {
let firstControlHasValue = (formGroup.controls[conditionalControlKey].value instanceof Array) ? formGroup.controls[conditionalControlKey].value.length > 0 :
!(formGroup.controls[conditionalControlKey].value === ""),
result = CustomValidators.controlsHaveValueCheck(controlKeys, formGroup);
formGroup.controls[conditionalControlKey].setErrors(null); // Also reset the conditional Control...
if (firstControlHasValue && formGroup.controls[conditionalControlKey].value !== false) {// also checks for false (for unchecked checkbox value)...
return (result.every((invalid) => {
return invalid === false;
})) ? null : {required: true};
}
}
}
return null;
}
}
此方法将根据conditionalControlKey
的值创建一组表单控件"required
",即如果conditionalControlKey
有一个值,则不需要controlKeys
数组中的所有其他控件,否则都需要全部。
我希望这对任何人都不会太复杂 - 我相信这些代码片段可以改进,但我觉得它们恰当地展示了一种解决这个问题的方法。
相关文章:
- Rad网格编辑模式通过选中复选框时的java脚本启用禁用所需的字段验证器
- 回发前所需的字段验证程序不起作用
- 将字段设置为有条件地使用所需的字段验证器
- .NET MVC 5 不显眼的禁用字段验证
- Liferay网络表单组件字段验证
- 输入字段验证的键代码函数在chrome中没有按预期工作
- MVC 5防止隐藏字段的必需字段验证
- jQuery字段验证-是否为空,以及正确的值
- JS如何捕获基于键入然后删除的字符的字段验证逻辑
- Javascript Wordpress字段验证匹配
- 字段验证器,它不允许移动到下一个字段
- 在更改另一个字段时触发Yii字段验证
- 进度条和所需字段验证器
- 字段验证:字段需要 JavaScript 正则表达式
- JS 字段验证 - 循环遍历对象,每个字段有三个数据注意事项
- Javascript 空字段验证 - 无法读取未定义的属性“值”
- 有没有办法知道 .net 必填字段验证器是否从 js 启用或禁用
- 避免在字段验证失败时调用 AJAX onsuccess
- 使用 jQuery 使用 asp.net 必填字段验证器验证必填字段
- 如何使用 Angular.js/Javascript 为 url 添加输入字段验证