edumarg
edumarg

Reputation: 88

Material-UI checkbox with react-hook-form V7 won't sent correct value when the cheked value is changed via logic

I'm using react-hook-form V7.14.2 and I'm using a Material-UI checkbox that can be checked by the user manually or will be automatically checked depending on the values of certain inputs. This is working OK.

The issue is that when submitting the form, if the check box was checked via logic, depending on the values of certain input, the value sent to the back end will be false. If the user manually checks the check box, then it will send the correct value. -True if checked-.

I read the documentation to migrate from V6 to V7 in react-hook-form page, as I was previously using V6 and the code works there. https://react-hook-form.com/migrate-v6-to-v7/

I also read some previous answers in Stackoverflow such as this one: material-ui checkbox with react-hook-form but with no success.

Here is my code:

import React, { useContext, useState, useEffect } from "react";
import Checkbox from "@material-ui/core/Checkbox";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCheckCircle } from "@fortawesome/free-solid-svg-icons";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import { Controller, set } from "react-hook-form";
import { makeStyles } from "@material-ui/core/styles";
import { DarkThemeContext } from "../../context/DarkThemeContext";
import { useStylesSelectPropDetails } from "../../styledComponent/SelectPropDetailsStyled";
import { IMAGES_LINK } from "../../api/doFetch";

const useStylesLabel = makeStyles((theme) => ({
  label: {
    fontSize: "1em",
    fontFamily: "Open Sans Hebrew, sans-serif !important",
    fontWeight: 400,
    lineHeight: 1.5,
  },
}));

const CheckboxPropDetails = ({
  register,
  name,
  label,
  checked,
  isShelter,
  isElevator,
}) => {
  const classesLabel = useStylesLabel();
  const [isDarkTheme] = useContext(DarkThemeContext);
  const [isChecked, setIsChecked] = useState(false);
  const props = { isDarkTheme: isDarkTheme };
  const classes = useStylesSelectPropDetails(props);

  const handleChange = (event) => {
    setIsChecked(event.target.checked);
  };

  useEffect(() => {
    if (name === "shelter") {
      if (  isShelter,) {
        setIsChecked(true);
      } else setIsChecked(false);
    }
    if (name === "elevator") {
      console.log("elevator");

      if (isElevator) {
        console.log("isElevator", isElevator);
        setIsChecked(true);
      } else setIsChecked(false);
    }
  }, [  isShelter, isElevator]);

  return (
    <>
      <FormControlLabel
        classes={classesLabel}
        control={
          <Checkbox
            name={name}
            id={name}
            defaultChecked={checked ? checked : false}
            {...register(name)}
            color="primary"
            size={"medium"}
            icon={
              <img
                src={`${IMAGES_LINK}/dashboard/elements/rec.svg`}
                alt="Circle"
                style={{ width: 20, height: 20 }}
              />
            }
            disableRipple
            checkedIcon={
              <FontAwesomeIcon
                icon={faCheckCircle}
                style={{ width: 20, height: 20 }}
              />
            }
            checked={isChecked}
            onChange={(e) => handleChange(e)}
          />
        }
        labelPlacement="end"
        label={<p className={classes.paragraphAddProp}>{label}</p>}
      />
    </>
  );
};

Code used with V6 on react-hook-form:

import React, { useContext, useState, useEffect } from "react";
import Checkbox from "@material-ui/core/Checkbox";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCheckCircle } from "@fortawesome/free-solid-svg-icons";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import { Controller } from "react-hook-form";
import { makeStyles } from "@material-ui/core/styles";
import { DarkThemeContext } from "../../context/DarkThemeContext";
import { useStylesSelectPropDetails } from "../../styledComponent/SelectPropDetailsStyled";
import { IMAGES_LINK } from "../../api/doFetch";

const useStylesLabel = makeStyles((theme) => ({
  label: {
    fontSize: "1em",
    fontFamily: "Open Sans Hebrew, sans-serif !important",
    fontWeight: 400,
    lineHeight: 1.5,
  },
}));

const CheckboxPropDetails = ({
  register,
  name,
  label,
  checked,
  isShelter,
  isElevator,
}) => {
  const classesLabel = useStylesLabel();
  const [isDarkTheme] = useContext(DarkThemeContext);
  const props = { isDarkTheme: isDarkTheme };
  const classes = useStylesSelectPropDetails(props);
  const [isChecked, setIsChecked] = useState(false);

  const handleChange = (event) => {
    console.log("event", event.target.checked);
    setIsChecked(event.target.checked);
  };

  useEffect(() => {
    if (name === "shelter") {
      if (isShelter) {
        setIsChecked(true);
      } else setIsChecked(false);
    }
    if (name === "elevator") {   
      if (isElevator) {
           setIsChecked(true);
      } else setIsChecked(false);
    }
  }, [isShelter, isElevator]);

  return (
    <>
      <FormControlLabel
        classes={classesLabel}
        control={
          <Checkbox
            name={name}
            defaultChecked={checked ? checked : false}
            inputRef={register}
            color="primary"
            size={"medium"}
            icon={
              <img
                src={`${IMAGES_LINK}/dashboard/elements/rec.svg`}
                alt="Circle"
                style={{ width: 20, height: 20 }}
              />
            }
            disableRipple
            checkedIcon={
              <FontAwesomeIcon
                icon={faCheckCircle}
                style={{ width: 20, height: 20 }}
              />
            }
            checked={isChecked}
            onChange={(e) => handleChange(e)}
          />
        }
        labelPlacement="end"
        label={<p className={classes.paragraphAddProp}>{label}</p>}
      />
    </>
  );
};

Control, register, and so are being pass as props from another component.

As mention before, it's working on V6. The difference in V6 and V7 is one line:

in V6

  inputRef={register}

in V7

  {...register(name)}

How could I make it so that when the checked value is change via logic that it will register and on submit will be send to the backend as true?

Upvotes: 3

Views: 5996

Answers (1)

knoefel
knoefel

Reputation: 6949

The MUI <Checkbox /> component has a slighty different interface for setting a value. The RHF value has to be set with checked prop.

In v6 you just passed register to the inputRef, but since v7 calling register will return an object - two properties of this object are value and onChange. So when spreading your register call to the MUI <Checkbox /> you're setting the link for the actual value to the value prop instead of using the checked prop.

You should therefore use RHF's <Controller /> component, check the docs here for more infos about integrating external controlled components.

<FormControlLabel
  control={
    <Controller
      name="checkbox"
      control={control}
      defaultValue={false}
      render={({ field: { value, ref, ...field } }) => (
        <Checkbox
          {...field}
          inputRef={ref}
          checked={!!value}
          color="primary"
          size={"medium"}
          disableRipple
        />
      )}
    />
  }
  label="Checkbox"
  labelPlacement="end"
/>

One important note: you have to set the value with checked={!!value} to avoid a warning about changing a component from uncontrolled to controlled in case that your defaultValue for someCheckbox is initially undefined.

Edit React Hook Form - Basic (forked)

Upvotes: 11

Related Questions