是的验证:需要一种语言的所有字段或不需要任何字段

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

joe*_*une 0

可以使用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