Max
Max

Reputation: 167

How to use Material UI Checkbox and Select onChange with useFieldArray of React Hook Form

I'm going to make checkbox and select fields with Material UI. However, I don't how to handle on change event. The dropdown isn't selected if I selected one item of list, and clicking the checkbox isn't checked.

Here is the code:

import React from "react";
import { useForm, useFieldArray } from "react-hook-form";
import {
  FormControlLabel,
  FormLabel,
  FormGroup,
  FormControl,
  Button,
  Box,
  MenuItem,
  Select,
  Checkbox
} from "@material-ui/core";
import "./styles.css";

export default function App() {
  const { register, setValue, control } = useForm({
    defaultValues: {
      infoGp: [
        {
          title: "",
          restricted: false,
          prohibited: false,
          bus: false,
          close: false
        }
      ]
    },
    mode: "onBlur"
  });

  const { fields, append, remove } = useFieldArray({
    control,
    name: "infoGp"
  });

  const handleAddItem = () => {
    append({
      title: "",
      restricted: false,
      prohibited: false,
      bus: false,
      close: false
    });
  };

  return (
    <div className="App">
      {fields.map((item, index) => {
        return (
          <Box border={1} p={3}>
            <Box mb={4}>
              <FormControl>
                <Select
                  name={`infoGp${index}.title`}
                  value={`${item.title}`}
                  // onChange={titleChange}
                  displayEmpty
                  ref={register}
                >
                  <MenuItem value="">Title</MenuItem>
                  <MenuItem value="mr">Mr.</MenuItem>
                  <MenuItem value="mrs">Mrs.</MenuItem>
                  <MenuItem value="miss">Miss</MenuItem>
                </Select>
              </FormControl>
            </Box>
            <Box>
              <FormControl component="fieldset">
                <FormLabel component="legend">Type of Location</FormLabel>
                <FormGroup className="permitType">
                  <FormControlLabel
                    control={
                      <Checkbox
                        checked={item.restricted}
                        inputRef={register}
                        // onChange={permitTypeChange}
                        name={`infoGp${index}.restricted`}
                      />
                    }
                    label="restricted"
                  />
                  <FormControlLabel
                    control={
                      <Checkbox
                        checked={item.prohibited}
                        inputRef={register}
                        // onChange={permitTypeChange}
                        name={`infoGp${index}.prohibited`}
                      />
                    }
                    label="prohibited"
                  />
                  <FormControlLabel
                    control={
                      <Checkbox
                        checked={item.bus}
                        inputRef={register}
                        // onChange={permitTypeChange}
                        name={`infoGp${index}.bus`}
                      />
                    }
                    label="bus stop"
                  />
                  <FormControlLabel
                    control={
                      <Checkbox
                        checked={item.close}
                        inputRef={register}
                        // onChange={permitTypeChange}
                        name={`infoGp${index}.close`}
                      />
                    }
                    label="close zone"
                  />
                </FormGroup>
              </FormControl>
            </Box>
            {index > 0 && (
              <Button
                variant="contained"
                color="secondary"
                onClick={() => remove(index)}
              >
                remove
              </Button>
            )}
          </Box>
        );
      })}
      <Box mt={5}>
        <Button variant="contained" color="primary" onClick={handleAddItem}>
          add item
        </Button>
      </Box>
    </div>
  );
}

Should I use setValues or setState to handle onChange?

codesandbox here: https://codesandbox.io/s/react-hook-form-field-array-on-checkbox-select-g6gq9?file=/src/App.js:0-3872

Upvotes: 2

Views: 2447

Answers (2)

BertC
BertC

Reputation: 2666

I have a FormCheckbox component with the MUI Checkbox in there.

That FormCheckbox is part of a UI Library in which we handle as much as possible.

The FormCheckbox component in the Pages Components should be as simple as possible and looks like this:


const onChangeSubscription = (e: ChangeEvent<HTMLInputElement>) => {
    console.log(`CheckBox Changed !!: Target Value = ${e.target.checked}`);
};
    
....

<FormCheckbox
    name={'subscription'}
    label={'Yes, I want a subscription'}
    onChange={onChangeSubscription}
/>

FormCheckbox component

The FormCheckbox component looks like this:

Making use of:

  • Written in Typescript
  • react-hook-form
  • @mui/material
  • @emotion/styled
import { ChangeEvent } from 'react';
import { useFormContext, Controller } from 'react-hook-form';
import { Checkbox as MuiCheckbox } from '@mui/material';
import Box from '@mui/material/Box';
import FormControlLabel from '@mui/material/FormControlLabel';
import styled from '@emotion/styled';

interface PropsInterface {
    name: string;
    value?: boolean;
    label: string;
    onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
}

const Checkbox = styled(MuiCheckbox)`
    padding-right: 10px;
`;

export const FormCheckbox = (props: PropsInterface) => {
    const { control, watch, setValue, getValues } = useFormContext();

    const { name, value, label, onChange } = props;
    const realValue = value ? value : false;

    const onChangeHandler = (e: ChangeEvent<HTMLInputElement>) => {
        setValue(name, !getValues()[name], {
            shouldDirty: true,
            shouldTouch: true,
            shouldValidate: true,
        });
        if (typeof onChange === 'function') {
            onChange(e);
        }
    };

    return (
        <Box>
            <Controller
                name={name}
                control={control}
                defaultValue={realValue}
                render={() => (
                    <FormControlLabel
                        control={
                            <Checkbox onChange={onChangeHandler} checked={watch(name)} />
                        }
                        label={label}
                    />
                )}
            />
        </Box>
    );
};

Upvotes: -1

iku
iku

Reputation: 1094

You can use Controller and control for the checkbox in react-hook-form version 7.

Here is an example: https://codesandbox.io/s/rhf-controller-material-ui-9ik00?file=/src/App.js

Upvotes: 1

Related Questions