Yup validation for object under array - reactjs

I am using Formik + Yup for form creation with validation. I have following initial value.
const initialValue = {
title: '',
schedules: [
{
maxGame: '',
bookingDuration: [],
reservationSlots: [
{
from: null,
to: null,
increment: '',
pricePerHours: [
{
guest: '',
price: ''
}
],
pricePerGame: [
{
type: 'Child',
price: ''
}
]
}
]
}
]
};
My current yup schema:
const schema = {Yup.object().shape({
title: Yup.string()
.min(2, 'Must be 2 characters or more')
.required('Title is required'),
schedules: Yup.array().of(
Yup.object().shape({
bookingDuration: Yup.array().when('maxGame', {
is: '',
then: Yup.array().min(1, 'Booking Duration is required'),
otherwise: Yup.array()
}),
maxGame: Yup.number().when('bookingDuration', {
is: (bookingDuration) => bookingDuration.length === 0,
then: Yup.number()
.min(1, 'Max Game must be greater than zero')
.required('Max Game is required either fill booking duration'),
otherwise: Yup.number()
}),
reservationSlots: Yup.array().of(
Yup.object().shape({
from: Yup.date().typeError('Invalid Time'),
to: Yup.date().typeError('Invalid Time'),
increment: Yup.string().required('Time Increment is required'),
pricePerGame: Yup.array().of(
Yup.object().shape({
type: Yup.string(),
price: Yup.string()
.when(['type'], {
is: (type) => type,
then: Yup.string().required('Price is required'),
}),
})
),
},
)
},
[['bookingDuration', 'maxGame']])
)
})
}
I want following validation:
Either one of bookingDuration and maxGame is required.
If bookingDuration.length > 0 then price of pricePerHours should be required.
If price of pricePerHours is filled then bookingDuration should be required.
If maxGame !== '' then price of pricePerGame should be required.
If price of pricePerGame is filled then maxGame should be required.
I am able to apply no. 1 validation but for rest unable to apply validation. Can you please help me on this.

Related

yup some validation is not working with react form hook in react

i am trying to include conditions in yup schema but fail with some validation.
const componentSchema = yup.object().shape(
{
type: yup.string().trim().required('Type is required!'),
label: yup.string().trim().required('Label is required!'),
visibilityDependentOn: yup.string(),
visibilityDependentOnWithOption: yup.string().when('visibilityDependentOn', {
is: '',
otherwise: yup.string().trim().required('Option is required'),
}),
options: yup.array().when('type', {
is: (value) => value === 'multiOptions' || value === 'options',
then: yup
.array()
.of(yup.object().shape({ label: yup.string().required(), value: yup.string().required() }).required())
.min(1, 'Atleast one options'),
}),
tableData: yup.array().when('type', {
is: 'tableData',
then: yup
.array()
.of(
yup.object().shape({
columnLabel: yup.string().trim().required('column Label is required!'),
columnType: yup.string().trim().required('column Type is required!'),
})
)
.required(),
}),
},
['type', 'options', 'visibilityDependentOn', 'visibilityDependentOnWithOption', 'tableData']
)
all the validation working fine except:
in options, the of(...) is not working but the min(...) is working fine.
in tableData same thing happens.
yup version
"yup": "0.32.8"

Using Yup and Formik, how to get index number when validating conditional property inside of fields array?

I need to show and validate "hourlyCommitment" field ONLY when "commitment" field has a value of "3". The problem is, I can't seem to access the "current index" of the array field, so the validation doesn't work. Any ideas would be appreciated
professionals: Yup.array().of(
Yup.object().shape({
talent: Yup.number().required(translates.FormsErrorsRequired),
seniority: Yup.number().required(translates.FormsErrorsRequired),
commitment: Yup.number().required(translates.FormsErrorsRequired),
hourlyCommitment: Yup.number()
.nullable()
.when('professionals[currentIndex].commitment', {
is: '3',
then: Yup.number().required(translates.FormsErrorsRequired),
}),
quantity: Yup.number().required(translates.FormsErrorsRequired),
skills: Yup.array().of(
Yup.object().shape({
value: Yup.string(),
label: Yup.string(),
})
),
})
),
Seems I solved it:
professionals: Yup.array().of(
Yup.object().shape({
talent: Yup.number().required(translates.FormsErrorsRequired),
seniority: Yup.number().required(translates.FormsErrorsRequired),
commitment: Yup.number().required(translates.FormsErrorsRequired),
hourlyCommitment: Yup.number().test({
name: 'hourlyCommitment',
exclusive: true,
message: translates.FormsErrorsRequired,
test: (value, context) => {
return !!value || context.parent.commitment !== 3;
},
}),
quantity: Yup.number().required(translates.FormsErrorsRequired),
skills: Yup.array().of(
Yup.object().shape({
value: Yup.string(),
label: Yup.string(),
})
),
})
),
Why don't you just use commitment in initial values?
Are they different values with professionals[current].commitment?
If yes, then define a variable called currentCommitment and set it to professionals[current].commitment, then use it in validation

Yup: Array of Object Conditional Validation

I have a data structure like this:
{
isReceivesSalary: true,
boardMembers: [
{
name: 'David',
country: 'USA',
additionalProperty: {
isReceivingSalary: true
}
},
{
name: 'Dave',
country: 'France',
additionalProperty: {
isReceivingSalary: false
}
}
]
}
When isReceivesSalary is checked then at least one of the boardMembers should have
property isReceivingSalary should be checked.
Below is my validation schema which is not working.
const boardMembersValidation ={
isReceivesSalary: yup.boolean().required(),
boardMembers: yup.array(yup.object.shape({
name: yup.string().required(),
country: yup.string().required(),
additionalProperty: yup.object().shape({
isReceivingSalary: yup.boolean()
})
}))
};
Is it possible to validate at least one of the boardMember should be receiving salary when isReceivesSalary is true?
Also add validation message.

React yup validation with and react-hook-form, array of different type of objects depends from one of object attribute

I have a form, where user can add with no limit ( add shareholder ).
Shareholder can be 2 different types ( NATURAL / LEGAL )
here is interface for thouse objects:
export interface shareholderNatural {
type: 'NATURAL';
firstName: string;
lastName: string;
personalCode: string;
sharePart: number;
politicallyExposed: boolean;
country: string;
position: string;
}
export interface shareholderLegal {
type: 'LEGAL';
companyName: string;
companyCode: string;
sharePart: number;
politicallyExposed: boolean;
country: string;
position: string;
}
I need validation for:
firstName, lastName, personalCode, sharePart if type is NATURAL
companyName, companyCode, sharePart if type is NATURAL
Attribut type is set by the select from the component state when user click opn add another sharehoilder button (useState)
I tryed to do it with Yup.array().when( 'key', {})
const validationSchema = Yup.object().shape({
shareholders: Yup.array().when('type', {
is: 'NATURAL',
then: Yup.array().of(
Yup.object().shape({
firstName: Yup.string().required(t('')),
lastName: Yup.string().required(t('')),
personalCode: Yup.string().required(t('')),
sharePart: Yup.number().required(t('')),
}),
),
otherwise: Yup.array().of(
Yup.object().shape({
companyName: Yup.string().required(t('')),
companyCode: Yup.string().required(t('')),
sharePart: Yup.number().required(t('')),
}),
),
}),
});
But in this case key attribute should be outside ...
Any help here ?
Thank you.
You can check every field separately. Just replace type with needed field:
const validationSchema = Yup.object().shape({
shareholders: Yup.array().of(
Yup.object().shape({
firstName: Yup.string().when('type', {
is: 'NATURAL',
then: Yup.string().required(t(''))
}),
lastName: Yup.string().when('type', {
is: 'NATURAL',
then: Yup.string().required(t(''))
}),
personalCode: Yup.string().when('type', {
is: 'NATURAL',
then: Yup.string().required(t(''))
}),
sharePart: Yup.number().required(t('')),
companyName: Yup.string().when('type', {
is: 'LEGAL',
then: Yup.string().required(t(''))
}),
companyCode: Yup.string().when('type', {
is: 'LEGAL',
then: Yup.string().required(t(''))
}),
})
)
)
};

Conditional Yup Validation is not working

I have formik form with below initialValues
const initialValues1 = {
people: [
{
id: Math.random(),
email: "",
isNewUser: true,
profile: {
firstName: "",
lastName: "",
}
}
]
};
I want to validate firstName and lastName only when is isNewUser is true by Yup I am trying below but it is not working. How can validate conditionally in Formik Yup
people: Yup.array().of(
Yup.object().shape({
isNewUser: Yup.boolean(),
profile: Yup.object().shape({
firstName: Yup
.string()
.when('isNewUser', {
is: true,
then: Yup.string().required("First name is required")
}),
})
})
)
formatted code in IDE
people: Yup.array().of(
Yup.object({
isNewUser: Yup.boolean(),
profile: Yup.object().when('isNewUser', {
is: true,
then: Yup.object({
firstName: Yup.string().required('First name is required'),
})
})
})
);
isNewUser is sibling of profile attribute, so we can use it in when for defining profile schema not it's child(first_name) schema directly.
you can also specify else part using otherwise key
when({ 'attrbute', is: 'func or value', then: 'schema if is true', otherwise: 'schema if is false'})
As per docs ,
Adjust the schema based on a sibling or sibling children fields. You
can provide an object literal where the key is is value or a matcher
function, then provides the true schema and/or otherwise for the
failure condition.
So move the isNewUser to reflect as sibling. Like this:
const initialValues1 = {
people: [
{
id: Math.random(),
email: "",
//isNewUser: true, // <--------------- remove this
profile: {
firstName: "",
lastName: "",
isNewUser: true // <---------------- here.
}
}
]
};

Resources