Conditional Validation in Yup
Solution 1
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
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
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
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
email: Yup.string()
.when(['showEmail', 'anotherField'], {
is: (showEmail, anotherField) => {
return (showEmail && anotherField);
},
then: Yup.string().required('Must enter email address')
}),
reectrix
Updated on December 27, 2021Comments
-
reectrix over 2 years
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?
-
DB1500 almost 5 yearsHow would this work with three possible values for showEmail? I.e. rather than a boolean() it was a string()
-
Devin Clark almost 5 yearsYou'll add a specific test to the is key using a function: is: (emailValue) => emailValue === "some test string you want it to match"
-
Mohsen Kamrani over 4 yearsThanks for the answer, I really have no idea how you came up with this solution but that reflects a major problem with many npm packages, i.e. 90 percent of the library documentation should be pulled from the Git issues or SO answers.
-
Swar Shah about 4 yearsUpdated codesandbox codesandbox.io/s/formik-conditional-val-1ldmx
-
J. Munson almost 3 years"best practice to ensure that all of you form's fields have initial values..." A pretty common example where this doesn't hold true is number inputs. Say that you want your input to start empty. Not with zero, not with any other number. You would have to initialize this field to undefined.
-
Gimnath almost 3 yearsYou saved a lot of time
-
Sergei Kurochkin over 2 yearskeep in mind, that there is "otherwise" key that is opposite to "then", where you can keep alternative validations
-
Neil Gaetano Lindberg about 2 yearsThis is so close to what I'm looking for. If you want to make sure END > START, how would you access the
end
value in the.when
here? I only want to compare ifstart
is set.