Reputation: 87
I'm trying to use react-hook-form with multi-select and select but it is not working. It worked with normal text field but not with select and multiselect. Here's my code. Thank you so much.
<div className="pricing__section80">
<div className="pricing__container-card70">
<MultiSelect
required="true"
labelledBy="Hora"
name="user_select7"
value={options.filter((obj) => date1.includes(obj.value))}
onChange={handleChange}
options={options}
{...register("user_select7", { required: true })}
/>
{errors.user_select7 && <h7>Porfavor llena este campo</h7>}
</div>
</div>
<div className="pricing__section80">
<div className="pricing__container-card77">
<Select
placeholder="Metodo de pago"
name="user_cash"
value={cash}
onChange={setCash}
options={options6}
{...register("user_cash", { required: true })}
/>
{errors.user_cash && <h7>Porfavor llena este campo</h7>}
</div>
</div>
Upvotes: 7
Views: 30367
Reputation: 39
You can use a custom register. Here is an example of my code
const {
register,
handleSubmit,
setValue,
watch,
formState: { errors },
} = useForm<TLoginInputs>({
defaultValues: {
[LoginFormEnum.MULTISELECT]: [],
},
criteriaMode: 'firstError',
});
const selectValue = watch(LoginFormEnum.MULTISELECT);
useEffect(() => {
register(LoginFormEnum.MULTISELECT, {
validate: {
required: (value) => value.length > 0 || 'required',
},
});
}, [register]);
const handleSelect = (value: Option[]) => {
setValue(LoginFormEnum.MULTISELECT, value);
};
return (
<form onSubmit={handleSubmit(handleSubmitForm)} noValidate>
<Multiselect
options={options}
onChange={handleSelect}
value={selectValue}
labelledBy="Multiselect"
textError={errors[LoginFormEnum.MULTISELECT]?.message} // custom props
/>
</form>
)
Upvotes: 0
Reputation: 51
I'm not going to paste a whole component but lets suppose you use MUI and useForm and want to add a field to your form that uses a select with multiple option set, here is the code:
<Grid item xs={12}>
<Stack spacing={1}>
<InputLabel htmlFor="records">
Records
</InputLabel>
<Controller
control={control}
name="records"
render={({ field: { onChange, value, name, ref } }) => (
<Select
id="records"
variant="outlined"
name={name}
ref={ref}
onChange={onChange}
multiple
fullWidth
defaultValue={initialValues.records}
renderValue={(selectedRecords) =>
selectedRecords.map(({ name }) => name).join(", ")
}
>
{recordOptions.map((record) => (
<MenuItem key={record.id} value={record}>
<Checkbox checked={isSelected(value, record)} />
<ListItemText primary={record.name} />
</MenuItem>
))}
</Select>
)}
/>
</Stack>
</Grid>
You can also make it work with just the register
method call, but I didn't try that. isSelected
is a function to test if your option is selected where value
is a list of what is currently selected
Upvotes: 0
Reputation: 429
Im using react-hook-form and react-multi-select-component
and im using Controller from rect-use-form
on your onSubmit function you have to modify the default data from Multiselect to match the data of useForm
const onSubmit = async (data) => {
....
const newRoles = data?.roles.map((element) => element.value);
const body = JSON.stringify({ ...data, roles: newRoles });
await fetch(url,..., body)
on your Multiselect component use Controller like this
....
const {
handleSubmit,
control,
formState: { errors },
} = useForm();
....
<Controller
control={control}
name="roles"
render={({ field: { onChange, value } }) => (
<MultiSelect
options={ROLES}
value={value ? value : []}
onChange={onChange}
labelledBy="Select"
disableSearch
hasSelectAll={false}
/>
)}
/>
....
Upvotes: 3
Reputation: 411
Just use mui-react-hook-form-plus
Here is an example:
import { HookSelect, useHookForm } from 'mui-react-hook-form-plus';
const defaultValues = {
person: {
firstName: 'Atif',
lastName: 'Aslam',
sex: '',
// pass array if multiselect
hobby: [],
},
};
const App = () => {
const { registerState, handleSubmit } = useHookForm({
defaultValues,
});
const onSubmit = (_data: typeof defaultValues) => {
alert(jsonStringify(_data));
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<HookSelect
{...registerState('person.sex')}
label='Sex'
items={[
{ label: 'MALE', value: 'male' },
{ label: 'FEMALE', value: 'female' },
{ label: 'OTHERS', value: 'others' },
]}
/>
{/* Multi select */}
<HookSelect
{...registerState('person.hobby')}
label='Hobby'
selectProps={{ multiple: true }}
items={[
{ label: 'Coding', value: 'coding' },
{ label: 'Debugging', value: 'debugging' },
{ label: 'Testing', value: 'testing' },
]}
/>
</form>
)
}
Repo: https://github.com/adiathasan/mui-react-hook-form-plus
Demo: https://mui-react-hook-form-plus.vercel.app/?path=/docs/
Upvotes: 0
Reputation: 1205
I had the same issue, I implemented react-select with useForm hook this way:
import Select from 'react-select';
// ... more code
const {
formState: { errors },
handleSubmit,
register,
control,
watch
} = useForm({
defaultValues: {}
});
// ... more code
<Controller
control={control}
name="categories"
render={({
field: { onChange, onBlur, value, name, ref },
}) => (
<Select
options={options}
isLoading={isLoading}
onChange={onChange}
isMulti={true}
onBlur={onBlur}
value={value}
name={name}
ref={ref}
/>
)}
/>
// ... more code
Upvotes: 5
Reputation: 4344
You need to wrap the controlled components with Controller
.
<Controller
control={control}
name="test"
render={({
field: { onChange, onBlur, value, name, ref },
fieldState: { invalid, isTouched, isDirty, error },
formState,
}) => (
<Checkbox
onBlur={onBlur} // notify when input is touched
onChange={onChange} // send value to hook form
checked={value}
inputRef={ref}
/>
)}
/>
You can read more on the official docs: https://react-hook-form.com/api/usecontroller/controller/
Upvotes: -2