Angular - FormArray 中的唯一性验证器
Angular - Uniqueness validator in FormArray
我创建了一个自定义验证器来验证我 FormArray
中的唯一性。当特定值 is/are 已经在数组中时,我想显示错误。
问题是它没有按预期工作。
实际行为:
重现步骤:
- 添加 3 "inputs" - 地址;
- 填写输入1;
- 用不同的值填充输入 2;
- 用与输入1相同的值填充输入3; (没有出现错误,无论是输入 1 还是输入 3)
预期行为:
如果相同的值出现在 "X groups" 中,它们的特定输入必须显示错误。
在上述情况下,错误应该出现在输入 1 和 3 上。
假设我有 4 个输入:
- 值:堆栈
- 值:溢出
- 值:堆栈
- 值:溢出
4 个输入必须显示错误,因为它们都是重复的。
static uniqueBy = (field: string, caseSensitive = true): ValidatorFn => {
return (formArray: FormArray): { [key: string]: boolean } => {
const controls = formArray.controls.filter(formGroup => {
return isPresent(formGroup.get(field).value);
});
const uniqueObj = { uniqueBy: true };
let found = false;
if (controls.length > 1) {
for (let i = 0; i < controls.length; i++) {
const formGroup = controls[i];
const mainControl = formGroup.get(field);
const val = mainControl.value;
const mainValue = caseSensitive ? val.toLowerCase() : val;
controls.forEach((group, index) => {
if (i === index) {
// Same group
return;
}
const currControl = group.get(field);
const tempValue = currControl.value;
const currValue = caseSensitive ? tempValue.toLowerCase() : tempValue;
let newErrors;
if ( mainValue === currValue) {
if (isBlank(currControl.errors)) {
newErrors = uniqueObj;
} else {
newErrors = Object.assign(currControl.errors, uniqueObj);
}
found = true;
} else {
newErrors = currControl.errors;
if (isPresent(newErrors)) {
// delete uniqueBy error
delete newErrors['uniqueBy'];
if (isBlank(newErrors)) {
// {} to undefined/null
newErrors = null;
}
}
}
// Add specific errors based on condition
currControl.setErrors(newErrors);
});
}
if (found) {
// Set errors to whole formArray
return uniqueObj;
}
}
// Clean errors
return null;
};
}
你可以在这里查看DEMO.
在您的代码中使用了嵌套的 for 循环,您在其中交织错误。
以下是每次迭代的验证状态查找方式:
0 [null, "{"uniqueBy":true}", null]
1 ["{"uniqueBy":true}", "{"uniqueBy":true}", null]
2 [null, "{}", null]
http://plnkr.co/edit/MTjzQ9KiJHJ56DVAZ155?p=preview(添加三个地址并观察输出)
在下面的代码中,我只在 for 循环语句之前清除错误一次,不再删除错误。
controls.map(formGroup => formGroup.get(field)).forEach(x => x.errors && delete x.errors['uniqueBy']);
for (let i: number = 0; i < controls.length; i++) {
const formGroup: FormGroup = controls[i] as FormGroup;
const mainControl: AbstractControl = formGroup.get(field);
const val: string = mainControl.value;
const mainValue: string = caseSensitive ? val.toLowerCase() : val;
controls.forEach((group: FormGroup, index: number) => {
if (i === index) {
return;
}
const currControl: any = group.get(field);
const tempValue: string = currControl.value;
const currValue: string = caseSensitive ? tempValue.toLowerCase() : tempValue;
let newErrors: any;
if ( mainValue === currValue) {
if (isBlank(currControl.errors)) {
newErrors = uniqueObj;
} else {
newErrors = Object.assign(currControl.errors, uniqueObj);
}
currControl.setErrors(newErrors);
find = true;
}
});
}
我无法添加评论,所以我只是将其作为新答案。我修改了 yurzui 的 plunker,因为在更正具有重复值的字段后表单仍然无效。
如何在 yurzui 的 plunker 中重现错误:
- 正确填写姓名
- 街道填写值'x'
- 添加街道值为 'x'
的新地址
- 将第二条街道更改为 'x'
以外的街道
表单仍然无效,因为第一个 'street' FormControl 的错误设置为“{}”而不是 null。我刚刚注意到 dev_054 在他原来的 post 中做到了,但无论如何,这里有一个 plunker 的变化:http://plnkr.co/edit/nQeQ01fjnTlcp3FgEnWL?p=preview
代码是:
controls.map(formGroup => formGroup.get(field)).forEach(x => x.errors && delete x.errors['uniqueBy']);
代码现在是:
controls.map(formGroup => formGroup.get(field)).forEach(x => {
if (x.errors) {
delete x.errors['unique-by'];
if (isBlank(x.errors)) {
x.setErrors(null);
}
}
});
在 plunker 中,我还修复了参数 caseSensitive 的解释方式。它现在可以正常工作了。
我创建了一个自定义验证器来验证我 FormArray
中的唯一性。当特定值 is/are 已经在数组中时,我想显示错误。
问题是它没有按预期工作。
实际行为:
重现步骤:
- 添加 3 "inputs" - 地址;
- 填写输入1;
- 用不同的值填充输入 2;
- 用与输入1相同的值填充输入3; (没有出现错误,无论是输入 1 还是输入 3)
预期行为:
如果相同的值出现在 "X groups" 中,它们的特定输入必须显示错误。
在上述情况下,错误应该出现在输入 1 和 3 上。
假设我有 4 个输入:
- 值:堆栈
- 值:溢出
- 值:堆栈
- 值:溢出
4 个输入必须显示错误,因为它们都是重复的。
static uniqueBy = (field: string, caseSensitive = true): ValidatorFn => {
return (formArray: FormArray): { [key: string]: boolean } => {
const controls = formArray.controls.filter(formGroup => {
return isPresent(formGroup.get(field).value);
});
const uniqueObj = { uniqueBy: true };
let found = false;
if (controls.length > 1) {
for (let i = 0; i < controls.length; i++) {
const formGroup = controls[i];
const mainControl = formGroup.get(field);
const val = mainControl.value;
const mainValue = caseSensitive ? val.toLowerCase() : val;
controls.forEach((group, index) => {
if (i === index) {
// Same group
return;
}
const currControl = group.get(field);
const tempValue = currControl.value;
const currValue = caseSensitive ? tempValue.toLowerCase() : tempValue;
let newErrors;
if ( mainValue === currValue) {
if (isBlank(currControl.errors)) {
newErrors = uniqueObj;
} else {
newErrors = Object.assign(currControl.errors, uniqueObj);
}
found = true;
} else {
newErrors = currControl.errors;
if (isPresent(newErrors)) {
// delete uniqueBy error
delete newErrors['uniqueBy'];
if (isBlank(newErrors)) {
// {} to undefined/null
newErrors = null;
}
}
}
// Add specific errors based on condition
currControl.setErrors(newErrors);
});
}
if (found) {
// Set errors to whole formArray
return uniqueObj;
}
}
// Clean errors
return null;
};
}
你可以在这里查看DEMO.
在您的代码中使用了嵌套的 for 循环,您在其中交织错误。
以下是每次迭代的验证状态查找方式:
0 [null, "{"uniqueBy":true}", null]
1 ["{"uniqueBy":true}", "{"uniqueBy":true}", null]
2 [null, "{}", null]
http://plnkr.co/edit/MTjzQ9KiJHJ56DVAZ155?p=preview(添加三个地址并观察输出)
在下面的代码中,我只在 for 循环语句之前清除错误一次,不再删除错误。
controls.map(formGroup => formGroup.get(field)).forEach(x => x.errors && delete x.errors['uniqueBy']);
for (let i: number = 0; i < controls.length; i++) {
const formGroup: FormGroup = controls[i] as FormGroup;
const mainControl: AbstractControl = formGroup.get(field);
const val: string = mainControl.value;
const mainValue: string = caseSensitive ? val.toLowerCase() : val;
controls.forEach((group: FormGroup, index: number) => {
if (i === index) {
return;
}
const currControl: any = group.get(field);
const tempValue: string = currControl.value;
const currValue: string = caseSensitive ? tempValue.toLowerCase() : tempValue;
let newErrors: any;
if ( mainValue === currValue) {
if (isBlank(currControl.errors)) {
newErrors = uniqueObj;
} else {
newErrors = Object.assign(currControl.errors, uniqueObj);
}
currControl.setErrors(newErrors);
find = true;
}
});
}
我无法添加评论,所以我只是将其作为新答案。我修改了 yurzui 的 plunker,因为在更正具有重复值的字段后表单仍然无效。
如何在 yurzui 的 plunker 中重现错误:
- 正确填写姓名
- 街道填写值'x'
- 添加街道值为 'x' 的新地址
- 将第二条街道更改为 'x' 以外的街道
表单仍然无效,因为第一个 'street' FormControl 的错误设置为“{}”而不是 null。我刚刚注意到 dev_054 在他原来的 post 中做到了,但无论如何,这里有一个 plunker 的变化:http://plnkr.co/edit/nQeQ01fjnTlcp3FgEnWL?p=preview
代码是:
controls.map(formGroup => formGroup.get(field)).forEach(x => x.errors && delete x.errors['uniqueBy']);
代码现在是:
controls.map(formGroup => formGroup.get(field)).forEach(x => {
if (x.errors) {
delete x.errors['unique-by'];
if (isBlank(x.errors)) {
x.setErrors(null);
}
}
});
在 plunker 中,我还修复了参数 caseSensitive 的解释方式。它现在可以正常工作了。