Controlling Material UI v4’s Checkbox with React Hook Form v7

programming
スポンサーリンク
language

In Controlling Material UI’s Checkbox with React Hook Form, I introduced how to control Material UI’s Checkbox with React Hook Form v6.

After that, React Hook Form v7 was released.
The way to control Material-UI has changed a little in React Hook Form v7, so I will show you how to control Checkbox in Material UI v4 with typescript.

The control specification of the Checkbox introduced here is the same as the previous one, as follows.

  • Support for initial values (default checks)
  • Control checkbox value changes
  • Set up Checkbox groups using Material UI (multiple checkboxes with the same name)

And the completed checkbox form is the following form.

スポンサーリンク

Sample Code

import React, { useState } from "react";
import { useForm, FieldValues, Controller } from "react-hook-form";
import Button from "@material-ui/core/Button";
import Checkbox from "@material-ui/core/Checkbox";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import FormGroup from "@material-ui/core/FormGroup";
import FormHelperText from "@material-ui/core/FormHelperText";
import FormControl from "@material-ui/core/FormControl";
import FormLabel from "@material-ui/core/FormLabel";

export default function App() {
  const [submitData, setSubmitData] = useState<string>("");
  const defaultCheckedValues = ["B"];

  // Options
  const options = [
    {
      title: "A"
    },
    {
      title: "B"
    },
    {
      title: "C"
    },
    {
      title: "D"
    }
  ];
  const {
    formState: { errors },
    control,
    setValue,
    getValues,
    handleSubmit
  } = useForm<FieldValues>({
    criteriaMode: "all",
    defaultValues: { checkbox: defaultCheckedValues.join(",") }
  });

  const handleFormOnSubmit = (data: any) => {
    setSubmitData(data.checkbox);
  };

  const handleCheck = (
    option: { title: string },
    event: React.ChangeEvent<{}>
  ) => {
    let values: string[] = getValues("checkbox")?.split(",") || [];
    values = values.filter((v) => v); // empty element deletion

    let newValues: string[] = [];
    if ((event.target as HTMLInputElement).checked) {
      newValues = [...(values ?? []), option.title];
    } else {
      newValues = values?.filter((value) => value !== option.title);
    }
    setValue("checkbox", newValues.join(","));

    return newValues.join(",");
  };

  return (
    <>
      <form
        method="POST"
        onSubmit={handleSubmit(handleFormOnSubmit)}
        encType="multipart/form-data"
      >
        <FormControl
          required
          error={errors?.hasOwnProperty("checkbox")}
          component="fieldset"
          fullWidth
        >
          <FormLabel component="legend">Question.</FormLabel>

          <FormHelperText>
            {errors?.checkbox && errors?.checkbox.message}
          </FormHelperText>

          <FormGroup>
            <Controller
              name="checkbox"
              control={control}
              rules={{ required: "Please make a selection." }}
              defaultValue=""
              render={({ field, fieldState }) => (
                <>
                  {options.map((option, i) => (
                    <FormControlLabel
                      {...field}
                      key={i}
                      label={option.title}
                      onChange={(event) =>
                        field.onChange(handleCheck(option, event))
                      }
                      control={
                        <Checkbox
                          defaultChecked={defaultCheckedValues.includes(option.title)}
                        />
                      }
                    />
                  ))}
                </>
              )}
            />
          </FormGroup>
        </FormControl>
        <Button type="submit" variant="contained" color="primary">
          Submit
        </Button>
      </form>
      <br />
      Submitted content.
      <br />
      {submitData}
    </>
  );
}

Description of the control that meets the requirements

The requirements to be controlled were as follows.
The following is an explanation of the code that corresponds to each requirement.

  • Support for initial values (default checks)
  • Control checkbox value changes
  • Set up Checkbox groups using Material UI (multiple checkboxes with the same name)

Corresponding to initial value

You can do this without using the React Hook Form where it corresponds to the default value.
Put the items to be checked by default in the Material-UI Checkbox in an array.

const defaultCheckedValues= ["B",];

The defaultValues in the following code defines the initial values for the React Hook Form.
defaultChecked.join(“,”) makes the array comma-separated characters.

const {
    formState: { errors },
    control,
    setValue,
    getValues,
    handleSubmit
  } = useForm<FieldValues>({
    criteriaMode: "all",
    defaultValues: { checkbox: defaultCheckedValues.join(",") }
  });

Next, define the default values for the Material-UI.
In the Checkbox defaultChecked, check if the defaultCheckedValues are filled with a value.
If the defaultCheckedValues are filled, defaultChecked will be true.

<Checkbox defaultChecked={defaultCheckedValues.includes(option.title)} />

You can now put a default check on it.

Control checkbox value changes.

When there is a change in the check box, the handleCheck function will be executed.

In the Within the handleCheck function, the following is done.

  • Delete the value of the changed item if it already exists
  • Add a value if there is no value for the changed item
const handleCheck = (
    option: { title: string },
    event: React.ChangeEvent<{}>
  ) => {
    // Get the checked values.
    let values: string[] = getValues("checkbox")?.split(",") || [];
    // empty element deletion
    values = values.filter((v) => v);

    // Reflect changes
    let newValues: string[] = [];
    if ((event.target as HTMLInputElement).checked) {
      // Add a value 
      newValues = [...(values ?? []), option.title];
    } else {
      // Exclude values
      newValues = values?.filter((value) => value !== option.title);
    }
    setValue("checkbox", newValues.join(","));

    return newValues.join(",");
  };

In the part to get the checked values, getValues() is used to get the checked values.
If there are no checked values, the values will be an empty array.

In the empty element removal part, the values retrieved by getValues() in React Hook Form v7 may contain empty values, so we exclude them.

useForm - getValues
Performant, flexible and extensible forms with easy-to-use validation.

Set up a Checkbox group in Material UI

To set up multiple Material UI Checkboxes, create a checkbox group in the render of the Controller of React Hook Form v7.

Be careful not to create multiple checkboxes for each React Hook Form v7 Controller.

<FormGroup>
  <Controller
    name="checkbox"
    control={control}
    rules={{ required: "Please make a selection." }}
    defaultValue=""
    render={({ field, fieldState }) => (
      <>
        {options.map((option, i) => (
          <FormControlLabel
            {...field}
            key={i}
            label={option.title}
            onChange={(event) =>
              field.onChange(handleCheck(option, event))
            }
            control={
              <Checkbox
                defaultChecked={defaultCheckedValues.includes(option.title)}
              />
            }
          />
        ))}
      </>
    )}
  />
</FormGroup>

To get the value of the Checkbox in Material-UI controlled by React Hook Form v7 and manipulate the value, you need to write onChange in the FormControlLabel.

Reference

useForm
Performant, flexible and extensible forms with easy-to-use validation.
TS Support
Performant, flexible and extensible forms with easy-to-use validation.
タイトルとURLをコピーしました