gpt4 book ai didi

javascript - Angular2 形式 : validator with interrelated fields

转载 作者:行者123 更新时间:2023-11-28 05:49:24 25 4
gpt4 key购买 nike

给出一个可以输入城市名称或其纬度和经度的表格。该表单将验证是否填写了城市名称,或者是否同时填写了纬度经度。纬度和经度如果已填充,则必须是数字。

我可以使用这三个字段创建一个 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 数组中的所有其他控件都不是必需的,否则所有控件都是必需的。

我希望这对任何人来说都不会太复杂 - 我确信这些代码片段可以改进,但我觉得它们恰本地展示了解决此问题的一种方法。

关于javascript - Angular2 形式 : validator with interrelated fields,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38204812/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com