Optional field validation in Yup schema - javascript

I'm using react-hook-form with yup for my form validation and want some fields to be optional (null).
Following their documentation, I'm using nullable() and optional() but it is still getting validated:
export const updateAddressSchema = yup.object({
address: yup
.string()
.nullable()
.optional()
.min(5, "Address must be more than 5 characters long")
.max(255, "Address must be less than 255 characters long"),
city: yup
.string()
.nullable()
.optional()
.max(32, "City name must be less than 32 characters long"),
postal_code: yup
.string()
.nullable()
.optional()
.length(10, "Postal code must be 10 characters long"),
phone: yup
.string()
.nullable()
.optional()
.min(10, "Phone number must be more than 10 characters long")
.max(20, "Phone number must be less than 20 characters long"),
});
Is there any right way to do this?

You need to use .when for conditional validation like this below. I have added only for address and city only, you can add for other like this.
export const updateAddressSchema = yup.object().shape({
address: yup.string().when("address", (val, schema) => {
if(val?.length > 0) { //if address exist then apply min max else not
return yup.string().min(5, "min 5").max(255, "max 255").required("Required");
} else {
return yup.string().notRequired();
}
}),
city: yup.string().when("city", (val, schema) => {
if(val?.length > 0) {
return yup.string().max(32, "max 32").required("Required");
}
else {
return yup.string().notRequired();
}
}),
}, [
["address", "address"],
["city", "city"],
] //cyclic dependency
);
Also, you need to add Cyclic dependency

Thanks a lot to #Usama for their answer and solution!
I experienced another problem when using their solution. My back-end API disregards null values and returns the previous value if null values are submitted. The problem was that on initial render the text field's value was null but after selecting and typing and then deleting the typed letters to get it empty again (without submitting), its value would change to an empty string and so my API would throw an error and wouldn't update the user info.
The way I managed to fix it was to use yup's .transform() method to transform the type from empty string to null if the text field wasn't filled:
export const updateAddressSchema = yup.object().shape(
{
address: yup.string().when("address", (value) => {
if (value) {
return yup
.string()
.min(5, "Address must be more than 5 characters long")
.max(255, "Address must be less than 255 characters long");
} else {
return yup
.string()
.transform((value, originalValue) => {
// Convert empty values to null
if (!value) {
return null;
}
return originalValue;
})
.nullable()
.optional();
}
}),
......................
},
[
["address", "address"],
......................,
]
);
I really hope this helps someone.

Related

Is it possible to show a string length inside of a yup error message?

Currently, our validation schema looks something like this:
const validationSchema = Yup.object().shape({
statuses: Yup.array().of(
value: Yup.string().when('deleted', {
is: false,
then: Yup.string()
.nullable()
.max(64, 'Must be less than 64 characters'),
}),
available_on_label: Yup.string().when('deleted', {
is: false,
then: Yup.string()
.nullable()
.max(15, 'Must be less than 15 characters'),
}),
})
),
})
I would like to make the error message on available_on_label show the current character count of that field. Something like:
.max(15, Must be less than 15 characters. (${Yup.String().length()} / 15)),
I have tried to access the string inside of the validation, and it doesn't seem to work.
ANSWER: YUP validation - how to get the value
Leaving this post in case it helps someone else source the answer
.max(15, (obj) => {
const length = obj.value.length;
return `Must be less than 15 characters (${length} / 15)`;
})

Yup validation - check if value doesn't match other field

Hi I am trying to find a way to compare 2 fields and validate only if they are not equal.
This is the only idea I was able to come up with but it doesn't work:
yup
.number()
.required()
.notOneOf(
[FormField.houseHoldMembers as any],
'error message',
),
Shorted:
const schema = yup.object({
field1: yup.number().required(),
field2: yup
.number()
.required()
.notOneOf([yup.ref('field1'), null], 'The two values should not be equal'),
});
You can compare the two values and validate only if they are not equal like this:
const mySchema = yup.object({
text1: yup.number().required(),
text2: yup
.number()
.required()
.when(["text1"], (text1, schema) => {
console.log(schema);
return schema.notOneOf([text1], "the two values should not be equal");
})
});
You can take a look at this sandbox for a live working example of this solution.

Why yup is trigger my tests even though previous tests are failing?

I want to validate my object with the schema using yup.
But I notice that when I wrote my own test function it's trigger anyway.
I mean I validate the age property for number, null, positive, integer value. then I want to continue with my own logic test.
So I expect to NOT enter the function unless the previous tests are valid.
I'm not sure if this is how it meant to be, but in this way I must also check for valid input in my tests function, even though I add the number, null, positive, integer checks.
So am I using the yup wrong?
What I expect form yup is not invoke the test if the previous tests are invalid.
stackblitz
import { object, string, number, date, InferType } from 'yup';
let userSchema = object({
age: number()
.nullable()
.positive()
.integer()
.test({
message: 'test message',
test: (v) => {
console.log('in test!', v);
return !!v.toPrecision();
},
}),
});
userSchema
.validate({ age: null })
.then((res) => {
console.log({ res });
})
.catch((e) => {
console.log({ e });
});

How to make custom error message using Joi?

How to make a custom message using joi? i saw many answered question related on this but i dont know why it didnt work on my end, the error message always appeared is "Student" does not contain 1 required value(s) what i want is "Student" This field is required.
export const VALIDATION_SCHEMA = {
students: Joi.array()
.label('Student Name(s)')
.items(
Joi.object({
name: Joi.string(),
value: Joi.string()
}).required().messages('"Student" This field is required.')
),
}
You can return a custom error object using Error constructor like this:
var schema = Joi.object().keys({
firstName: Joi.string().min(4).max(8).required().error(new
Error('error message here for first name')),
lastName: Joi.string().min(5).max(1).required().error(new
Error('error message here for last name'))
});
Joi.validate(req.body, schema, function(err, value) {
if (err) {
console.log(err.message)
return catched(err.message);
}
});
The easiest way in my opinion would be this.
const Joi = require("#hapi/joi");
export const categorySchema = Joi.object({
mobile: Joi.string().trim().regex(/^[6-9]\d{9}$/).required().messages({
"string.base": `"" should be a type of string`,
"string.empty": `"" must contain value`,
"string.pattern.base": `"" must be 10 digit number`,
"any.required": `"" is a required field`
}),
password: Joi.string().trim().required().messages({
"string.base": `"" should be a type of 'text'`,
"string.pattern.base": `"" must be 10 digit number`,
"any.required": `"" is a required field`
}),
}).required();

Conditionally Validation in Yup

How to implement the condition like value of 1 field should always be greater than the value of another field.
here's my schema
value: Yup.number().required(''),
value2: Yup.number().when('value',{
is: (val) => something here
then: Yup.number().required('Required').positive('value should be positive'),
otherwise: Yup.number()
})
I want to check for value2 to always be > value.
How to access value2's value in the when condition?
I'm not sure it's the right way to do it, but I'm using test.
Like this:
yourField: Yup.string().test('should-be-greather-than-yourField2', 'Should be greather than yourfield 2', function(value) {
const otherFieldValue = this.parent.yourField2
if (!otherFieldValue) {
return true;
}
return value > otherFieldValue;
})
Try this if you want to compare more than condition between two fields
import * as Yup from 'yup';
value: Yup.number().required(''),
value2: Yup.number().required()
.moreThan(
Yup.ref('value'),
'Should be more than value2'
)
I'm not sure, but try is: (val) => Yup.number().moreThan(val)
I am validating same fields for email and mobile no so user can validate both is same field.
username: yup
.string().when({
is : value =>isNaN(value),
then: yup.string().required('email/mobileno is required') .matches( Regex.EMAIL_REGX,
'Invalid email',
),
otherwise: yup.string()
.matches(Regex.PHONENO_REGX, StringUtils.phoneNo)
}),

Categories

Resources