React Hook Form Multiple Dropdown Validation
Currently I am using semantic ui css multiple dropdown validation. How do I validate the dropdown so that user has to choose at least ONE option before submitting ?
Right now the current output is that if I submit the form WITHOUT choosing any option, the error message appears.
However, if I choose an option and the submit, the error message still appears.
Following is my code.
import React, { useState } from 'react'
import { Button, Checkbox, Form, Dropdown } from 'semantic-ui-react'
//validation dependencies
import { useForm, Controller } from "react-hook-form";
import { yupResolver } from '@hookform/resolvers/yup';
import * as Yup from 'yup';
function TestForm() {
const validationSchema = Yup.object().shape({
firstName: Yup.string()
.required('firstName is required')
.min(6, 'firstName must be at least 6 characters')
,
options: Yup
.object()
.shape({
key: Yup.number().required("key is required (from label)"),
value: Yup.string().required("Value is required")
})
.nullable() // for handling null value when clearing options via clicking "x"
.required("options is required (from outter null check)")
});
const formOptions = { mode: 'all', reValidateMode: 'onChange', resolver: yupResolver(validationSchema) };
const { register, handleSubmit, reset, formState: { errors }, watch, setValue, control } = useForm(formOptions);
const [stateOptions, setStateOptions] = useState([
{
key: 1,
text: 'aaaa',
value: 'a'
},
{
key: 2,
text: 'bbbb',
value: 'b'
},
{
key: 3,
text: 'cccc',
value: 'c'
},
]);
console.log(watch())//For Debugging
const onSubmitHandler = (data) => {
console.log({ data });
setValue('firstName', 'dash', { shouldDirty: true, shouldValidate: true })
}
return (
<div>
<Form reply onSubmit={handleSubmit(onSubmitHandler)}>
<Form.Field>
<label>First Name</label>
<input placeholder='First Name' name="firstName" {...register('firstName')} />
<div className="invalid-feedback">{errors.firstName?.message}</div>
</Form.Field>
<Form.Field>
<Controller
name="options"
control={control}
render={({ field }) => (
<Dropdown
{...field}
placeholder='State'
fluid
multiple
search
selection
options={stateOptions}
/>
)}
/>
<div className="invalid-feedback">{errors.options?.message || errors.options?.value.message}</div>
</Form.Field>
<Form.Field>
<Button type='submit'>Submit</Button>
</Form.Field>
</Form>
</div>
)
}
export default TestForm
Solution 1:
Since Dropdown
component in semantic-ui-react
doesn't support ref
attribute, so you need to controll the value of DropDown
by yourself, here is an example you can try on it:
const options = [
{
key: 1,
text: 'aaaa',
value: 'a',
},
{
key: 2,
text: 'bbbb',
value: 'b',
},
{
key: 3,
text: 'cccc',
value: 'c',
},
]
function TestForm() {
const validationSchema = Yup.object().shape({
firstName: Yup.string()
.required('firstName is required')
.min(6, 'firstName must be at least 6 characters'),
options: Yup.array()
.of(Yup.object()
.shape({
key: Yup.number().required('key is required (from label)'),
value: Yup.string().required('Value is required'),
}))
.test(
"required",
"options is required",
(value) => Array.isArray(value) && value.length > 0
),
});
const formOptions = {
mode: 'all',
reValidateMode: 'onChange',
resolver: yupResolver(validationSchema),
};
const {
register,
handleSubmit,
formState: { errors },
setValue,
control,
} = useForm(formOptions);
const onSubmitHandler = (data) => {
console.log(data);
};
return (
<div>
<Form reply onSubmit={handleSubmit(onSubmitHandler)}>
<Form.Field>
<label>First Name</label>
<input
placeholder="First Name"
name="firstName"
{...register('firstName')}
/>
<div className="invalid-feedback">{errors.firstName?.message}</div>
</Form.Field>
<Form.Field>
<Controller
name="options"
control={control}
render={({ field }) => {
let { value, ...other } = field;
return (
<Dropdown
{...other}
placeholder="State"
fluid
multiple
search
selection
options={options}
value={Array.isArray(value) ? value.map(v => v.value) : []}
onChange={(e,{value})=> {
const values = value.map(v => options.find(item => item.value == v));
setValue('options', values)
}}
/>
);
}}
/>
<div className="invalid-feedback">
{errors.options?.message || errors.options?.value.message}
</div>
</Form.Field>
<Form.Field>
<Button type="submit">Submit</Button>
</Form.Field>
</Form>
</div>
);
}