Use react-hook-form with select and multiselect
Asked Answered
M

6

7

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>
Modiolus answered 12/5, 2022 at 23:5 Comment(0)
B
5

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
Byer answered 22/9, 2022 at 3:46 Comment(0)
Y
3

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}
                />
              )}
            />

....
Yolanthe answered 12/10, 2022 at 21:13 Comment(1)
do you have any idea how to add a Controller rule to require the user to select at least one option on form submit?Parmentier
M
0

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/

Mahau answered 11/10, 2022 at 2:26 Comment(0)
A
0

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

Autarch answered 6/4, 2023 at 18:30 Comment(0)
P
0

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>
)
Protagonist answered 26/8, 2024 at 18:52 Comment(0)
E
-2

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/

Eltonelucidate answered 12/5, 2022 at 23:24 Comment(1)
Thank. Sorry to ask. Can you give me an example with multiselect? Thank youModiolus

© 2022 - 2025 — McMap. All rights reserved.