Conditional Validation in Yup

JavascriptReactjsYupFormik

Javascript Problem Overview


I have an email field that only gets shown if a checkbox is selected (boolean value is true). When the form get submitted, I only what this field to be required if the checkbox is checked (boolean is true).

This is what I've tried so far:

    const validationSchema = yup.object().shape({
       email: yup
             .string()
             .email()
             .label('Email')
             .when('showEmail', {
                 is: true,
                 then: yup.string().required('Must enter email address'),
             }),
        })

I've tried several other variations, but I get errors from Formik and Yup:

Uncaught (in promise) TypeError: Cannot read property 'length' of undefined at yupToFormErrors (formik.es6.js:6198) at formik.es6.js:5933 at <anonymous> yupToFormErrors @ formik.es6.js:6198

And I get validation errors from Yup as well. What am I doing wrong?

Javascript Solutions


Solution 1 - Javascript

You probably aren't defining a validation rule for the showEmail field.

I've done a CodeSandox to test it out and as soon as I added:

showEmail: yup.boolean()

The form started validation correctly and no error was thrown.

This is the url: https://codesandbox.io/s/74z4px0k8q

And for future this was the correct validation schema:

validationSchema={yup.object().shape({
    showEmail: yup.boolean(),
    email: yup
      .string()
      .email()
      .when("showEmail", {
        is: true,
        then: yup.string().required("Must enter email address")
      })
  })
}

Solution 2 - Javascript

Formik author here...

To make Yup.when work properly, you would have to add showEmail to initialValues and to your Yup schema shape.

In general, when using validationSchema, it is best practices to ensure that all of you form's fields have initial values so that Yup can see them immediately.

The result would look like:

<Formik 
  initialValues={{ email: '', showEmail: false }}
  validationSchema={Yup.object().shape({
    showEmail: Yup.boolean(),
    email: Yup
      .string()
      .email()
      .when("showEmail", {
        is: true,
        then: Yup.string().required("Must enter email address")
      })
  })
}

/>

Solution 3 - Javascript

Totally agree with @João Cunha's answer. Just a supplement for the use case of Radio button.

When we use radio button as condition, we can check value of string instead of boolean. e.g. is: 'Phone'

const ValidationSchema = Yup.object().shape({
  // This is the radio button.
  preferredContact: Yup.string()
    .required('Preferred contact is required.'),
  // This is the input field.
  contactPhone: Yup.string()
    .when('preferredContact', {
      is: 'Phone',
      then: Yup.string()
        .required('Phone number is required.'),
    }),
  // This is another input field.
  contactEmail: Yup.string()
    .when('preferredContact', {
      is: 'Email',
      then: Yup.string()
        .email('Please use a valid email address.')
        .required('Email address is required.'),
    }),

});

This the radio button written in ReactJS, onChange method is the key to trigger the condition checking.

<label>
  <input
    name="preferredContact" type="radio" value="Email"
    checked={this.state.preferredContact == 'Email'}
    onChange={() => this.handleRadioButtonChange('Email', setFieldValue)}
  />
  Email
</label>
<label>
  <input
    name="preferredContact" type="radio" value="Phone"
    checked={this.state.preferredContact == 'Phone'}
    onChange={() => this.handleRadioButtonChange('Phone', setFieldValue)}
  />
  Phone
</label>

And here's the callback function when radio button get changed. if we are using Formik, setFieldValue is the way to go.

handleRadioButtonChange(value, setFieldValue) {
  this.setState({'preferredContact': value});
  setFieldValue('preferredContact', value);
}

Solution 4 - Javascript

You can even use a function for complex cases . Function case helps for complex validations

validationSchema={yup.object().shape({
    showEmail: yup.boolean(),
    email: yup
      .string()
      .email()
      .when("showEmail", (showEmail) => {
        if(showEmail)
          return yup.string().required("Must enter email address")
      })
  })
}

Solution 5 - Javascript

email: Yup.string()
    .when(['showEmail', 'anotherField'], {
        is: (showEmail, anotherField) => {
            return (showEmail && anotherField);
        },
        then: Yup.string().required('Must enter email address')
    }),

Solution 6 - Javascript

I use yup with vee-validate

vee-validate

here is the sample code from project

const schema = yup.object({
	first_name: yup.string().required().max(45).label('Name'),
	last_name: yup.string().required().max(45).label('Last name'),
	email: yup.string().email().required().max(255).label('Email'),
	self_user: yup.boolean(),
	company_id: yup.number()
		.when('self_user', {
			is: false,
			then: yup.number().required()
		})
})
const { validate, resetForm } = useForm({
	validationSchema: schema,
	initialValues: {
		self_user: true
	}
})

const {
	value: self_user
} = useField('self_user')
const handleSelfUserChange = () => {
	self_user.value = !self_user.value
}

Solution 7 - Javascript

it works for me very well :

   Yup.object().shape({
    voyageStartDate:Yup.date(),
    voyageEndDate:Yup.date()
        .when(
            'voyageStartDate',
            (voyageStartDate, schema) => (moment(voyageStartDate).isValid() ? schema.min(voyageStartDate) : schema),
        ),
})

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionreectrixView Question on Stackoverflow
Solution 1 - JavascriptJoão CunhaView Answer on Stackoverflow
Solution 2 - JavascriptjaredpalmerView Answer on Stackoverflow
Solution 3 - JavascriptEric TanView Answer on Stackoverflow
Solution 4 - Javascriptsridhar..View Answer on Stackoverflow
Solution 5 - JavascriptpareshmView Answer on Stackoverflow
Solution 6 - JavascriptOzal ZarbaliyevView Answer on Stackoverflow
Solution 7 - JavascriptSamiraView Answer on Stackoverflow