Reputation: 8629
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?
Upvotes: 192
Views: 380741
Reputation: 313
Using Yup ^1.6 without Typescript overload complaining
validationSchema={yup.object().shape({
showEmail: yup.boolean(),
email: yup
.string()
.email()
.when("showEmail", {
is: true,
then(schema): {
return schema.required("Must enter email address");
}
})
})
}
Upvotes: 0
Reputation: 181
for typescript using this
reasonContractNotDone: yup.string().when('isContractDone', {
is: false,
then: (schema) => schema.required('Must enter email address')
}),
NOT like below!
reasonContractNotDone: yup.string().when('isContractDone', {
is: false,
then: yup.string().required("Must enter email address")
}),
Upvotes: 13
Reputation: 1
If the condition is supposed to come from the outside of the form (for example you have more generic approach to creating validations, and have more abstraction above), you can also do something like this:
export const getNameFieldValidation = (isRequired?: boolean) => {
const fieldSchema = yup
.string()
.transform((value) => stringParser.parseToNoExtraSpaces(value));
if (isRequired) {
return fieldSchema.concat(yup.string().required());
}
return fieldSchema;
};
Upvotes: 0
Reputation: 533
Attention anyone using Yup v1
and upper. v1.2
in my case.
According to the official docs you have to do (schema) => ...
in you conditions
Official Docs:
For schema with dynamic components (references, lazy, or conditions), describe requires more context to accurately return the schema description. In these cases provide options
import { ref, object, string, boolean } from 'yup';
let schema = object({
isBig: boolean(),
count: number().when('isBig', {
is: true,
then: (schema) => schema.min(5),
otherwise: (schema) => schema.min(0),
}),
});
schema.describe({ value: { isBig: true } });
Upvotes: 16
Reputation: 11593
Checking for a specific value without using the function notation:
If select choice
has value date
, then input field date
is required:
availableDate: yup.string().when('choice', {
is: (v) => v === 'date',
then: (schema) => schema.required('date is required')
})
Upvotes: 2
Reputation: 1919
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 your 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")
})
})
}
/>
Upvotes: 90
Reputation: 1
This Code Works For ME Try To use It
const validation = () => {
try {
let userSchema = Yup.object().shape({
date: Yup.string().required(),
city: Yup.string().required(),
gender: Yup.string().required(),
email: Yup.string()
.matches(
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|.
(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-
Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
)
.nullable(true),
userName: Yup.string().min(3),
});
userSchema.validateSync({
email: email,
userName: userName,
gender: gender.name,
city: city.name,
date: date,
});
} catch (error) {
console.log(error);
setError({
userName: '',
email: '',
gender: '',
city: '',
date: '',
[error.path]: error.name,
});
}
};
Upvotes: 0
Reputation: 2133
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, schema) => {
if(showEmail)
return schema.required("Must enter email address")
return schema
})
})
}
Upvotes: 49
Reputation: 2753
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),
),
})
Upvotes: 4
Reputation: 638
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
}
Upvotes: 1
Reputation: 4984
email: Yup.string()
.when(['showEmail', 'anotherField'], {
is: (showEmail, anotherField) => {
return (showEmail && anotherField);
},
then: Yup.string().required('Must enter email address')
}),
Upvotes: 20
Reputation: 1463
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);
}
Upvotes: 26
Reputation: 10307
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")
})
})
}
Upvotes: 212