I am using state to get all form values.
const [CheckoutInput, setCheckoutInput] = useState({ name: "", street: "", postal: "", city: "", });
On form submit i would like to verify all javascript object values (By Looping CheckoutInput state), if it was empty i need update error value state.
const [ErrVal, setErrVal] = useState(CheckoutInput);
const checkErr = Object.values(CheckoutInput);
checkErr.forEach((entry) => {
if (CheckoutInput[entry]) {
setErrVal({ entry: "PLease fill the form" });
}
});
I'm failing to loop over all values after submit the form
I Cannot able to setErrVal state, if object has empty values.
Thank you.
I tried to do the validation using yup with react hook form. When the first checkbox is enabled I want to make the second checkbook required. When the second checkbox is enabled remaining fields should be required.
yup.object().shape({
firstName: yup.string().required(),
age: yup.number().required().positive().integer(),
website: yup.string().url(),
h1: yup.boolean(),
h2: yup.boolean().test("required", "h2 required", function validator(val) {
const { h1 } = this.parent;
return h1;
})
and my codesandbox link is https://codesandbox.io/s/react-hook-form-validationschema-forked-pmcgo?file=/src/index.js:178-471
How to fix this issue
As both h1 and h2 are in the same level of the object, you can use when on the h2.
From yup docs:
let schema = object({
foo: array().of(
object({
loose: boolean(),
bar: string().when('loose', {
is: true,
otherwise: (s) => s.strict(),
}),
}),
),
});
I have 3 fields phone1, phone2 and phone3.
I want to do a validation so it should alert if all are empty. Means if any one of these 3 field have value then the validation should Pass and don't alert.
I have used Yup library for this.
Right now I have create below code which actually requires all the 3 fields. Which I don't want.
yup.object().shape({
phone1: yup
.string()
.required("Please enter Phone 1"),
phone2: yup
.string()
.required("Please enter Phone 2"),
phone3: yup
.string()
.required("Please enter Phone 3"),
});
I belive I have to use .test() method of Yup JS which allows custom validation but I am not sure how I can write it in this situation. I am using Express framework to read requests.
const schema = yup.object().shape({
phone1: yup.string().when(['phone2', 'phone3'], {
is: (phone2, phone3) => !phone2 && !phone3,
then: yup.string().required('Please enter one of the three fields')
}),
phone2: yup.string().when(['phone1', 'phone3'], {
is: (phone1, phone3) => !phone1 && !phone3,
then: yup.string().required('Please enter one of the three fields')
}),
phone3: yup.string().when(['phone1', 'phone2'], {
is: (phone1, phone2) => !phone1 && !phone2,
then: yup.string().required('Please enter one of the three fields')
})
}, [['phone1', 'phone2'], ['phone1', 'phone3'], ['phone2','phone3']])
Then you can check this validation through this way:
schema.validate({ phone1: '', phone2: '', phone3: '' }).catch(function (err) {
console.log(err.errors[0]);
});
Enter any of the three fields for getting no error message.
e.g
schema.validate({ phone1: '', phone2: '123', phone3: '' }).catch(function (err) {
console.log(err.errors[0]);
});
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?
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")
})
})
}
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")
})
})
}
/>
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
})
})
}
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);
}
email: Yup.string()
.when(['showEmail', 'anotherField'], {
is: (showEmail, anotherField) => {
return (showEmail && anotherField);
},
then: Yup.string().required('Must enter email address')
}),
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),
),
})
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
}
So I made my own user adding form so that only logged in users can add new ones. Here's my Jade:
template(name="userAdd")
.sixteen.wide.column
h1 Add new user
form#userAddForm.ui.form
.field.required
label(for="username") Username:
input(type="text" name="username")#username
.field.required
label(for="email") Email:
input(type="email" name="email")#email
.field.required
label(for="password") Password:
input(type="password" name="password")#password
.field.required
label(for="realname") Real Name:
input(type="text" name="realname")#realname
.field.required
label(for="bio") Bio:
textarea(rows="3" name="bio")#bio
button(type="submit")#usersubmit.ui.button.primary Submit
And the Javascript:
Template.userAdd.events({
'click #usersubmit': function (evt) {
Accounts.createUser({
username: $('input #username').val(),
email: $('input #email').val(),
password: $('input #password').val(),
profile: {
realname: $('input #realname').val(),
bio: $('input #bio').val()
}
})
Router.go('/')
}
})
For some reason, this only redirects me back to the same page and doesn't do anything, not even something shows in the dev console. What am I doing wrong?
Because it is actually submitting the form. You need to stop the form from submitting. Use the following code.
Template.userAdd.events({
'submit form': function(event){
event.preventDefault();
Accounts.createUser({
username: event.target.username.value,
email: event.target.email.value,
password: event.target.password.value,
profile: {
realname: event.target.realname.value,
bio: event.target.bio.value
}
});
Router.go('/');
}
});
Notice that I use event.target.inputName.value which is the best practice way of dealing with form data in Meteor.