reactjscheckboxmaterial-uiformikformik-material-ui

Handling Multiple Checkboxes with Material UI and Formik


I have a form with a checkbox group containing 4 checkboxes within. I need to pass the value to my api on submit of button which is to be handled through Formik.

There are a few conditions on clicking a particular checkbox:

  1. If Height is checked, rest all should be checked as well
  2. If Breadth is checked, except for Height all should be checked
  3. If Length is checked, Both Nos and Length should be checked

Nos can be checked or left unchecked

Currently I'm declaring individual states for all checkboxes and declaring individual functions for each of the conditions mentioned above.

Is there any other way to bind the values from the checkbox to Formik and pass to the api

State and Individual Functions:

const [nos, setNos] = useState(false);
const [length, setLength] = useState(false);
const [breadth, setBreadth] = useState(false);
const [height, setHeight] = useState(false);

const handleHeight = e => {
  setNos(!nos);
  setLength(!length);
  setBreadth(!breadth);
  setHeight(!height);
};

const handleBreadth = e => {
  setNos(!nos);
  setLength(!length);
  setBreadth(!breadth);
};

const handleLength = e => {
  setNos(!nos);
  setLength(!length);
};

const handleNos = e =>{
  setNos(!nos);
};

Form with Formik:

const formik = useFormik({
    initialValues,
    validationSchema,
    onSubmit: async (values) => {
      alert(JSON.stringify(values, null, 2));
    },
});

return (
    <>
      <form
        onKeyDown={onKeyDown}
        id="newJobDetails"
        name="newJobDetails"
        onSubmit={formik.handleSubmit}
        className={CommonClasses.formPartStyling}
        style={{
          height: SetFormSize(
            isAdd ? "Add" : textFieldDisable ? "Info" : "Edit",
            1
          ),
          marginTop: marginTop || "none",
        }}
      >
        <div
          className={CommonClasses.headingTextOfForms}
          style={{ marginLeft: "4%", marginTop: "2%" }}
        >
          Add Jobs
        </div>
        <Divider
          style={{
            marginTop: "1%",
            marginBottom: "3%",
            color: "white",
          }}
        ></Divider>
        <div
          style={{
            marginLeft: "4%",
            marginTop: "2%",
          }}
        >
          <Grid container>
            <Grid item xs={6}>
              <LabelStyling>Job Name</LabelStyling>
              <TextField
                id="jobName"
                name="jobName"
                variant="outlined"
                placeholder="Enter Job Name"
                value={formik.values.jobName}
                onChange={formik.handleChange}
                size="small"
                style={{
                  width: FORM_PART_VARS.INPUT_BOX_WIDTH,
                }}
              />
            </Grid>
            <Grid item xs={6}>
              <LabelStyling>Stage</LabelStyling>
              <DropDown
                id="stage"
                width={FORM_PART_VARS.INPUT_BOX_WIDTH}
                value={formik.values.stage}
                onChange={formik.handleChange}
                error={formik.touched.stage && Boolean(formik.errors.stage)}
                helperText={formik.touched.stage && formik.errors.stage}
                mapFile={Stage}
                placeholder="Select Stage"
              />
            </Grid>
          </Grid>
        </div>
        <div
          style={{
            marginLeft: "4%",
            marginTop: "2%",
          }}
        >
          <Grid container>
            <Grid item xs={6}>
              <LabelStyling>Measurement</LabelStyling>
              <TextField
                id="measurement"
                name="measurement"
                variant="outlined"
                placeholder="Enter Measurement"
                value={formik.values.measurement}
                onChange={formik.handleChange}
                size="small"
                style={{
                  width: FORM_PART_VARS.INPUT_BOX_WIDTH,
                }}
              />
            </Grid>
            <Grid item xs={6}>
              <LabelStyling>Measurement Unit</LabelStyling>
              <DropDown
                id="measurement_unit"
                width={FORM_PART_VARS.INPUT_BOX_WIDTH}
                value={formik.values.measurement_unit}
                onChange={formik.handleChange}
                error={
                  formik.touched.measurement_unit &&
                  Boolean(formik.errors.measurement_unit)
                }
                helperText={
                  formik.touched.measurement_unit &&
                  formik.errors.measurement_unit
                }
                mapFile={MeasurementUnit}
                placeholder="Select Unit"
              />
            </Grid>
          </Grid>
        </div>
        <div
          style={{
            marginLeft: "4%",
            marginTop: "2%",
          }}
        >
          <Grid container>
            <Grid item xs={6}>
              <LabelStyling>Rate</LabelStyling>
              <TextField
                name="jobRate"
                id="jobRate"
                variant="outlined"
                placeholder="Enter Rate"
                value={formik.values.jobRate}
                onChange={formik.handleChange}
                size="small"
                style={{
                  width: FORM_PART_VARS.INPUT_BOX_WIDTH,
                }}
              />
            </Grid>
            <Grid item xs={6}>
              <LabelStyling>Service Rate</LabelStyling>
              <TextField
                name="serviceRate"
                id="serviceRate"
                variant="outlined"
                placeholder="Enter Service Rate"
                value={formik.values.serviceRate}
                onChange={formik.handleChange}
                size="small"
                style={{
                  width: FORM_PART_VARS.INPUT_BOX_WIDTH,
                }}
              />
            </Grid>
          </Grid>
        </div>
        <div
          style={{
            marginLeft: "4%",
            marginTop: "4%",
          }}
        >
          
            <LabelStyling>Select Measurement(s)</LabelStyling>
            
                <FormGroup row>
                <FormControlLabel control={<CheckBox checked={nos} onChange={handleNos} name="Nos" id="1"/>} label="Nos" />
                <FormControlLabel control={<CheckBox checked={length} onChange={handleLength}  name="Length" id="2"/>} label="Length" style={{marginLeft: "15px"}}/>
                <FormControlLabel control={<CheckBox checked={breadth} onChange={handleBreadth}  name="Breadth" id="3"/>} label="Breadth" style={{marginLeft: "15px"}}/>
                <FormControlLabel control={<CheckBox checked={height} onChange={handleHeight} name="Height" id="4"/>} label="Height" style={{marginLeft: "15px"}}/> 
           </FormGroup>
            
         
        </div>
        <div
          style={{
            marginLeft: "4%",
            marginTop: "4%",
          }}
        >
          <LabelStyling>Select Job Type</LabelStyling>
          <FormGroup row>
            <FormControlLabel control={<CheckBox name="jobType" value="Residential"/>} label="Residential"/>
            <FormControlLabel control={<CheckBox name="jobType" value="Commercial"/>} label="Commercial"/>
            <FormControlLabel control={<CheckBox name="jobType" value="Infrastructure"/>} label="Infrastructure"/>
          </FormGroup>
        </div>
      </form>
    </>
  );

Solution

  • When using Formik , it is not needed to maintain additional state to capture the form field values Formik will take care of that .

    In this case , since we need to programmatically change the values of other inputs based on a change in one input we can make use of the setFieldValue prop provided by Formik .

    Working Sandbox