动态更改数组自定义验证中的 Yup 消息。返回数组错误消息

huangapple go评论48阅读模式
英文:

Dynamically change Yup message in Array custom validation. Return Array error messages

问题

Problem: But when .test() function returns an array - I have an error string (not array string).

Solution: We can get the array like this:

arrayValidation.validate(["test UNIQUE", "fail", "fail"])
    .then(result => console.log("success: ", result))
    .catch(error => console.log("error: ", error.errors)) // => our array

BUT how to get the array in Formik? For some reason, I get only a string and not an array.

Here is an example:

import { useFormik } from "formik";
import * as Yup from "yup";
import { useEffect } from "react";

export const arrayValidation =
    Yup.array()
        .min(1)
        .max(5)
        .of(Yup.string().required("Required"))
        .test(
            'unique',
            (value) => {
                const message = "The value must be unique, but you have a copy in the field "
                const uniqueFieldIds: (string | null)[] = [];

                for (let i = 0; i < value.originalValue.length; i++) {
                    const targetStr = value.originalValue[i];

                    for (let j = 0; j < value.originalValue.length; j++) {
                        const str = value.originalValue[j];

                        if (j !== i && targetStr === str) {
                            uniqueFieldIds.push(message + (j + 1));
                            break;
                        }
                    }

                    if (!uniqueFieldIds[i]) {
                        uniqueFieldIds[i] = null;
                    }
                }

                console.log("uniqueFieldIds: ", uniqueFieldIds);
                return uniqueFieldIds;
            },
            (value) => {
                return value ? value.length === new Set(value)?.size : true;
            }
        )

arrayValidation.validate(["test UNIQUE", "fail", "fail"])
    .then(result => console.log("success: ", result))
    .catch(error => console.log("error: ", error.errors))

const TestComponent = () => {
    const formik = useFormik({
        initialValues: {
            arrayStrings: ["test UNIQUE", "fail", "fail"],
        },
        validationSchema: Yup.object({
            arrayStrings: arrayValidation,
        }),
        onSubmit: (values, { setSubmitting }) => {
            // ...
            setSubmitting(false);
        }
    });

    useEffect(() => {
        formik.submitForm();
    }, [])

    useEffect(() => {
        console.log("errors: ", formik.errors.arrayStrings); // "errors occurred" (string)
        console.log("TYPEOF errors: ", typeof formik.errors.arrayStrings); // string (not object)
        console.log("errors: ", (formik.errors.arrayStrings as any).errors); // undefined
    }, [formik.errors])

    return (
        <div>
        </div>
    )
}

export default TestComponent;

What am I doing wrong? Thanks for your answers.

英文:

Task:<br>I need to check every element in the array - unique item.
And I want to show the user, where exactly he has failure string(like a, in the second and third fields you have an identical values).<br>

My solution<br>
So, I found a solution using Yup.Array().test(...), and more concrete there it is:

export const arrayValidation =
    Yup.array()
        .min(1)
        .max(5)
        .of(Yup.string().required(&quot;Required&quot;))
        .test(
            &#39;unique&#39;,
            (value) =&gt; {
                const message = &quot;The value must be an unique, but you have the copy in the field &quot;
                const uniqueFieldIds: (string | null)[] = [];

                for (let i = 0; i &lt; value.originalValue.length; i++) {
                    const targetStr = value.originalValue[i];

                    for (let j = 0; j &lt; value.originalValue.length; j++) {
                        const str = value.originalValue[j];

                        if(j !== i &amp;&amp; targetStr === str) {
                            uniqueFieldIds.push(message + (j + 1));
                            break;
                        }
                    }

                    if (!uniqueFieldIds[i]) {
                        uniqueFieldIds[i] = null;
                    }
                }

                console.log(&quot;uniqueFieldIds: &quot;, uniqueFieldIds);
                return uniqueFieldIds;
            },
            (value) =&gt; {
                return value ? value.length === new Set(value)?.size : true;
            }
        )

arrayValidation.validate([&quot;test UNIQUE&quot;, &quot;fail&quot;, &quot;fail&quot;])
    .then(result =&gt; console.log(&quot;success: &quot;, result))
    .catch(error =&gt; console.log(&quot;error: &quot;, error)) // =&gt; Why is it not the array?

Problem<br>
But when .test() function returns an array - I have an error string(not array string).<br>
If array has 2 identical lines, then error is "2 error occured", but test() return value is array, soft of

[&quot;The value must be an unique, but you have the copy in the field 2&quot;, &quot;The value must be an unique, but you have the copy in the field 1&quot;]

EDIT:
We can get the array just like that:

arrayValidation.validate([&quot;test UNIQUE&quot;, &quot;fail&quot;, &quot;fail&quot;])
    .then(result =&gt; console.log(&quot;success: &quot;, result))
    .catch(error =&gt; console.log(&quot;error: &quot;, error.errors)) // =&gt; our array 

BUT how to get the array in the formik? For some reason I get only string, and not array.

Here is an example:

import {useFormik} from &quot;formik&quot;;
import * as Yup from &quot;yup&quot;;
import {useEffect} from &quot;react&quot;;

export const arrayValidation =
    Yup.array()
        .min(1)
        .max(5)
        .of(Yup.string().required(&quot;Required&quot;))
        .test(
            &#39;unique&#39;,
            (value) =&gt; {
                const message = &quot;The value must be an unique, but you have the copy in the field &quot;
                const uniqueFieldIds: (string | null)[] = [];

                for (let i = 0; i &lt; value.originalValue.length; i++) {
                    const targetStr = value.originalValue[i];

                    for (let j = 0; j &lt; value.originalValue.length; j++) {
                        const str = value.originalValue[j];

                        if(j !== i &amp;&amp; targetStr === str) {
                            uniqueFieldIds.push(message + (j + 1));
                            break;
                        }
                    }

                    if (!uniqueFieldIds[i]) {
                        uniqueFieldIds[i] = null;
                    }
                }

                console.log(&quot;uniqueFieldIds: &quot;, uniqueFieldIds);
                return uniqueFieldIds;
            },
            (value) =&gt; {
                return value ? value.length === new Set(value)?.size : true;
            }
        )

arrayValidation.validate([&quot;test UNIQUE&quot;, &quot;fail&quot;, &quot;fail&quot;])
    .then(result =&gt; console.log(&quot;success: &quot;, result))
    .catch(error =&gt; console.log(&quot;error: &quot;, error.errors))

const TestComponent = () =&gt; {
    const formik = useFormik({
        initialValues: {
            arrayStrings: [&quot;test UNIQUE&quot;, &quot;fail&quot;, &quot;fail&quot;],
        },
        validationSchema: Yup.object({
            arrayStrings: arrayValidation,
        }),
        onSubmit: (values, {setSubmitting}) =&gt; {
            // ...
            setSubmitting(false);
        }
    });

    useEffect(() =&gt; {
        formik.submitForm();
    }, [])

    useEffect(() =&gt; {
        console.log(&quot;errors: &quot;, formik.errors.arrayStrings); // &quot;errors occurred&quot; (string)
        console.log(&quot;TYPEOF errors: &quot;, typeof formik.errors.arrayStrings); // string, (not object)
        console.log(&quot;errors: &quot;, (formik.errors.arrayStrings as any).errors); // undefined
    }, [formik.errors])

    return (
        &lt;div&gt;
        &lt;/div&gt;
    )
}

export default TestComponent;

What am I doing wrong?<br>
Thanks for your answers

答案1

得分: 0

根据我理解,使用React似乎没有一种正常的方法。是的,你可以在纯JavaScript中执行这个操作:

arrayValidation.validate(["test UNIQUE", "fail", "fail"])
    .then(result => console.log("success: ", result))
    .catch(error => console.log("error: ", error.errors)) // error.errors对象

但在React+Formik中,你只能:
1)使用strArray.toString()连接结果字符串,或者使用strArray.join()作为示例。
2)然后你需要在Formik中解析这个字符串。
3)然后使用解析后的值。

感谢@usama 的评论,这些评论有助于创建这个答案。

英文:

As far as I understand there are no a normal way using React. Yes, you'll be able to do this in vanilla js:

arrayValidation.validate([&quot;test UNIQUE&quot;, &quot;fail&quot;, &quot;fail&quot;])
    .then(result =&gt; console.log(&quot;success: &quot;, result))
    .catch(error =&gt; console.log(&quot;error: &quot;, error.errors)) // error.errors object

But in the React+Formik you can only:

  1. concatenate resulting string using strArray.toString() or example using strArray.join().
  2. Then you ought to parse this string in the formik.
  3. And then use the value from the parsed string

Thanks to @usama for the comments that helped to create this answer

huangapple
  • 本文由 发表于 2023年3月4日 05:52:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75632176.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定