Joi validation: value is required if another value is equal to something - javascript

I would like to make the email value not required when status is equal to "Prospect", how can I do it? This is what I've tried so far.
status: Joi.string()
.required(),
email: Joi.string()
.email({ tlds: { allow: false } })
.when('status', { is: Joi.not('Prospect'), then: Joi.required() })

Related

JOI Verification is accepting invalid inputs

As you can see in my console log, the validation schema is working when I lead the input with an illegal character. However, if the illegal character is between legal ones, it wrongly verifies the input.
const UserLoginSchema = Joi.object({
username: Joi.string()
.required()
.min(3)
.max(30)
.pattern(new RegExp(`^[a-zA-Z0-9_.]`)),
password: Joi.string()
.min(6)
.required()
.min(6)
.max(30)
.pattern(new RegExp(`^[a-zA-Z0-9_.+-]+$`)),
});

Why is mongoose changing variable

It seems like mongoose (5.6.11) is changing my value in a query. Is this normal? Is there a way to keep the string case the same?
console.log('>>',req.body.visitor)
Visitor.findOne({ email: req.body.visitor.email }).then((visitor)=>{
....
server console/log:
>> {
email: 'Maida_VonRueden#hotmail.com',//this is a fake email generated with faker
enteredValidationCode: '969621'
}
Mongoose: visitors.findOne({ email: 'maida_vonrueden#hotmail.com' }, { projection: {} })
// ^ Why does the email change here?
Do I have to use regex to query case insensitive (Visitor.findOne({email: {$regex: new RegExp(req.body.visitor.email, 'i')}}))?
Based on #AKX comment my schema required lowercase
email: {
type: String,
unique: true,
lowercase: true, // < HERE
required: [true, 'cant be blank'],
match: [/\S+#\S+\.\S+/, 'is invalid'],
index: true
}
Per doc
boolean, whether to always call .toLowerCase() on the value

Joi validation display custom error message

Hi I am using "#hapi/joi": "^15.1.1". Unfortunately, I can't update to the latest Joi version right now.
This is my validation schema
const schema = {
name: Joi.string()
.allow("")
.max(30),
addLine1: Joi.string()
.required()
.label("Address Line 1"),
locality: Joi.string()
.required()
.label("City"),
region: Joi.string()
.required()
.label("State"),
zipCode: Joi.number()
.required()
.label("Zip Code"),
phoneNo: Joi.string()
.required("Required")
.regex(/^[0-9]{3}\-[0-9]{3}\-[0-9]{4}$/)
};
Then I validate and display the first error that occurred
const result = Joi.validate(this.state.addressDetails, this.schema, {
abortEarly: true,
});
return const errors = result.error.details[0].message;
This works. The only problem is I want to display a custom error message instead of the default one.
Default error message for address is "Address Line 1" is not allowed to be empty"
Instead of this, I want to display "Address is required!"
For the regex default one is
phoneNo with value "555" fails to match the required pattern: /^[0-9]{3}\-[0-9]{3}\-[0-9]{4}$/
Instead, I want to display please enter a valid phone number
How could I achieve this with version 15.1.1.
Newer versions messages thing won't help here.
Try out to return the message from the .error callback
addLine1: Joi.string()
.required()
.label("Address Line 1").error(()=>'"Address Line 1" is not allowed to be empty'),

Validate if one out of 3 field is not empty using Yup JS

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]);
});

Conditional Validation in Yup

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
}

Categories