skip to Main Content

I need to validate the form as follows: all fields in the form are optional, but if at least one field has a value entered, they all become mandatory.

I wrote:

const getRequiredSchema = () => {
   return Yup.string().when(["full_name", "email", "password"], {
     is: (...args) => args.some((item) => !!item),
     then: Yup.string().required("Required!")
   });
 };
...
validationSchema: Yup.object({
      full_name: getRequiredSchema(),
      email: getRequiredSchema(),
      password: getRequiredSchema()
})

And got an error: Cyclic dependency, node was:"password"
OK, I rewrote the code, trying to get rid of looping:

const getRequiredSchema = (field) => {
  return Yup.string().when(
    ["full_name", "email", "password"].filter((f) => f !== field),
    {
      is: (...args) => args.some((item) => !!item),
      then: Yup.string().required("Required!")
    }
  );
};
....
validationSchema: Yup.object({
      full_name: getRequiredSchema("full_name"),
      email: getRequiredSchema("email"),
      password: getRequiredSchema("password")
})

But the error did not disappear. How to write validation correctly?
Here is the full cole on codesandbox

2

Answers


  1. You can try this code, If you want to stick with Yup, one workaround could be to remove the circular dependency by creating a custom validation function that checks if at least one field has a value.

    import React from "react";
    import { useFormik } from "formik";
    import * as Yup from "yup";
    
    const validationSchema = (values) => {
      return Yup.object().shape({
        full_name: values.email || values.password ? Yup.string().required("Required") : Yup.string(),
        email: values.full_name || values.password ? Yup.string().required("Required") : Yup.string(),
        password: values.full_name || values.email ? Yup.string().required("Required") : Yup.string()
      });
    };
    
    export default function App() {
      const formik = useFormik({
        initialValues: {
          full_name: "",
          email: "",
          password: ""
        },
        validationSchema: () => validationSchema(formik.values),
        onSubmit: (values) => {
          alert(JSON.stringify(values, null, 2));
        }
      });
    
      return (
        <div className="App">
          <form onSubmit={formik.handleSubmit}>
            <div>
              <label>Full Name</label>
              <input
                type="text"
                name="full_name"
                maxLength="10"
                value={formik.values.full_name}
                onChange={formik.handleChange}
              />
              {formik.errors.full_name && formik.touched.full_name && (
                <p>{formik.errors.full_name}</p>
              )}
            </div>
            <div>
              <label>Email</label>
              <input
                type="email"
                name="email"
                value={formik.values.email}
                onChange={formik.handleChange}
              />
              {formik.errors.email && formik.touched.email && (
                <p>{formik.errors.email}</p>
              )}
            </div>
            <div>
              <label>Password</label>
              <input
                type="password"
                name="password"
                value={formik.values.password}
                onChange={formik.handleChange}
              />
              {formik.errors.password && formik.touched.password && (
                <p>{formik.errors.password}</p>
              )}
            </div>
    
            <div>
              <button type="submit">Submit</button>
            </div>
          </form>
        </div>
      );
    }
    
    Login or Signup to reply.
  2. Try Yup Lazy

    const validationSchema = Yup.lazy((values) => {
      const {full_name, email, password} = values
      if (full_name || email || password) {
        return Yup.object().shape({
          full_name: Yup.string().required(),
          email: Yup.string().required(),
          password: Yup.string().required(),
        })
      }
      return Yup.mixed().notRequired()
    })
    

    Working example: https://codesandbox.io/s/react-formik-yup-forked-s6w7y3?file=/src/App.js

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search