san*_*oco 5 forms validation yup formik
我们有一个相当大的表单,带有多语言输入 - 几个字段:
如果已填写一个德语字段,则应填写所有其他德语字段。其他语言也是如此。德国和法国的场地应该都可以填满,但意大利的场地可以是空的。
不知何故我无法让它工作。这是我尝试过的:
Yup.object().shape({
name_german: Yup.string().test(
'requireAllIfOneIsFilled',
'formvalidation.required.message',
function () {
return multiLanguageTest(this.parent, 'german');
},
),
... // same for other fields
});
Run Code Online (Sandbox Code Playgroud)
然后像这样进行测试:
const multiLanguageTest = (formValues, language: 'german' | 'french' | 'italian'): boolean => {
const errorCount = dependentFields.reduce((errorCount, rawFieldName) => {
const postFixedField = `${rawFieldName}_${language}`;
if (!formValues[postFixedField]) {
return errorCount + 1;
}
return errorCount;
}, 0);
return errorCount === 0;
};
Run Code Online (Sandbox Code Playgroud)
这给了我一种相当不可调试的行为。我是否使用了错误的概念.test?
可以使用context调用时传入的选项以这种方式进行验证.validate。
该context选项的一个简单但说明性的示例 - 将require_name键(带有truthy值)传递给.validate调用将把架构更改为.required():
const NameSchema = yup.string().when(
'$require_name',
(value, schema) => value ? schema.required() : schema
);
const name = await NameSchema.validate('joe', {
context: {
require_name: true,
}
});
Run Code Online (Sandbox Code Playgroud)
如果我们可以在验证期间将必填字段传递给架构,则我们可以将以下架构用于您的验证案例:
const AllOrNoneSchema = yup.object({
name_german: yup.string()
.when('$name_german', (value, schema) => value ? schema.required() : schema),
description_german: yup.string()
.when('$description_german', (value, schema) => value ? schema.required() : schema),
date_german: yup.string()
.when('$date_german', (value, schema) => value ? schema.required() : schema),
// ...other_languages
});
Run Code Online (Sandbox Code Playgroud)
在您的情况下,如果填写了一个或多个字段,我们必须为每种语言传递所需的上下文键。即,如果已填写一个德语字段,我们希望传递一个包含所有${something}_german值为 true 的键的对象:
{
name_german: true,
description_german: true,
...
}
Run Code Online (Sandbox Code Playgroud)
为此,我们可以创建一个辅助函数,它接受表单对象并返回包含boolean值的记录,如上例所示:
const createValidationContext = (form) => {
const entries = Object.entries(form);
const requiredLanguages = entries.reduce((acc, [key, value]) => {
return !value.length ? acc : [...acc, key.split('_')[1]];
}, []);
return Object.fromEntries(
entries.map(([key, value]) => [key, requiredLanguages.includes(key.split('_')[1])])
)
};
Run Code Online (Sandbox Code Playgroud)
总而言之,我们有以下可行的解决方案:
const yup = require("yup");
const AllOrNoneSchema = yup.object({
name_german: yup.string()
.when('$name_german', (value, schema) => value ? schema.required() : schema),
description_german: yup.string()
.when('$description_german', (value, schema) => value ? schema.required() : schema),
date_german: yup.string()
.when('$date_german', (value, schema) => value ? schema.required() : schema),
});
const createValidationContext = (form) => {
const entries = Object.entries(form);
const requiredLanguages = entries.reduce((acc, [key, value]) => {
return !value.length ? acc : [...acc, key.split('_')[1]];
}, []);
return Object.fromEntries(
entries.map(([key, value]) => [key, requiredLanguages.includes(key.split('_')[1])])
)
};
const form = {
description_german: "nein",
date_german: "juli",
name_german: "nena",
}
const formContext = createValidationContext(form);
console.log(formContext); // { description_german: true, date_german: true, name_german: true }
const validatedForm = await AllOrNoneSchema.validate(form, { context: formContext });
console.log(validatedForm); // { description_german: "nein", date_german: "juli", name_german: "nena" }
Run Code Online (Sandbox Code Playgroud)
该解决方案的实时示例(具有多种语言)可以在 RunKit 上进行测试,此处: https: //runkit.com/joematune/6138ca762dc6340009691d8a
有关 Yup contextapi 的更多信息,请在此处查看他们的文档: https: //github.com/jquense/yup#mixedwhenkeys-string--arraystring-builder-object--value-schema-schema-schema