I'm using react-hook-form for form submitting, and I need to make the validation work dynamically. For example, in the form, the category has three options: 'firstCateogory', 'secondCategory', 'thirdCategory'.
If the user chooses the category "firstCategory", the schema should be dynamically changed: the version input should be changed from 'Yup.string().nullable()' to 'Yup.string().nullable().required('Version is required')', required while the other two category options don't have the version required validation.
const Schema = Yup.object().shape({
category: Yup.string().nullable().required('Category is required'),
title: Yup.string().nullable().required('Title is required'),
version: Yup.string().nullable()
});
const DynamicSchema = Yup.object().shape({
category: Yup.string().nullable().required('Category is required'),
title: Yup.string().nullable().required('Title is required'),
version: Yup.string().nullable().required('Version is required')
});
const methods = useForm({
resolver: yupResolver(Schema),
defaultValues,
});
const {
getValues,
setValue,
watch,
handleSubmit,
formState: { isSubmitting },
} = methods;
...
return (
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
<RHFSelect
name="category"
label="Category">
{CATEGORY.map((item) => (
<MenuItem >
{item.label}
</MenuItem>
))}
</RHFSelect>
{watch('category') === 'firstCategory' && (
<RHFTextField
name="version"
label="Version"
/>
)}
I've read a lot of things about this issue, but nothing really helped. In this following code, I've tried to make the resolver dynamically change, but I couldn't use watch method here, it is not defined yet.
resolver: yupResolver(Schema), // resolver: watch('category') === 'firstCategory' ? yupResolver(Schema) : yupResolver(DynamicSchema)
defaultValues,
});
Is there a way to use the resolver dynamically change?
This is the code that I've changed based on your answer.
import {Controller, useForm} from 'react-hook-form';
const Schema = Yup.object().shape({
category: Yup.string().nullable().required('Category is required'),
title: Yup.string().nullable().required('Title is required'),
version: Yup.string().when('category', (value) => {
if (value[0] === 'category1') {
return Yup.string().required('Version is required')
} else if (value[0] === 'category2' || value[0] === 'category3') {
return Yup.string().nullable()
}
}),
});
const {
getValues,
setValue,
watch,
handleSubmit,
control,
formState: { isSubmitting, errors },
} = useForm({
resolver: yupResolver(Schema),
defaultValues,
});
...
return (
<FormProvider onSubmit={handleSubmit(onSubmit)}>
<FormControl>
<Controller
name="category"
control={control}
render={({field}) => (
<RHFSelect
{...field}
label={<EssentialLabel text="Category" />}
>
{CATEGORY_LIST.map((item) => (
<MenuItem key={item.code}
value={item.code}
onClick={() =>
field.onChange(item)
}>
{item.label}
</MenuItem>
))}
</RHFSelect>
)}
/>
</FormControl>
</FormProvider>
)
To achieve dynamic validation there is no need for two separate schemas, you can implement a single schema and dynamically apply validation rules based on the field value and using when. Below I am giving my code of how I performed dynamic validation