Search code examples
javascriptreactjsformikyup

Yup conditional validation based on a a non field value


I am trying to create a yup schema where based on a variables value the schema changes slightly. In my case depending on the value of prop myCondition I need to make a field as required. I would like to know if there is any better way I can achieve the same using Yup. Here's my current code structure that works:

// config.js
const COMMON_SCHEMA = {
  str1: yup
    .string()
    .nullable()
    .required('Please input str1'),
  str3: yup
    .string()
    .nullable()
};
const VALIDATION_SCHEMA_1 = yup.object().shape({
  ...COMMON_SCHEMA,
  str2: yup.string().nullable(),
});

const VALIDATION_SCHEMA_2 = yup.object().shape({
  ...COMMON_SCHEMA,
  str2: yup
    .string()
    .nullable()
    .required('Please input str2'),
});

const SCHEMAS = {
  VALIDATION_SCHEMA_1,
  VALIDATION_SCHEMA_2
}
export default SCHEMAS;

the following is how I conditionally choose different schemas:

// app.js
import SCHEMAS from './config';
...

<Formik
  validationSchema={
    this.props.myCondition === true
      ? SCHEMAS.VALIDATION_SCHEMA_1
      : SCHEMAS.VALIDATION_SCHEMA_2
  }
>
...
</Formik>

I feel like I can achieve whatever I am doing above in an easier way with yup. One of the approaches I tried was to pass in the prop myCondition into config file and work with it's value by using yup.when() but when only works if the value you want to use is also a part of the form so I couldn't achieve the same.


Solution

  • This can be achieved by the following way:

    You can wrap your schema in a function and pass your conditional prop:

    const wrapperSchema = (condition) => 
      Yup.object().shape({
        ...COMMON_SCHEMA,
        str2: yup.string()
         .when([], {
           is: () => condition === true,
           then: yup.string().nullable(),
           otherwise: yup.string().required('Please input str2'),
         }),
      });
    

    Please note that first param of when is a required param, you can also pass e.g. ["title", "name"] where title and name can be your field values, and you can retrieve and use them in is callback, in the same order, if you have to.