Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reactjs - Material UI- reduc form framework - grouped checkbox required validation error fixing to have at least one checkbox required

enter image description here

I am working on a react project and have built a form framework which wraps material ui, around the redux form.

** sandbox https://codesandbox.io/s/condescending-banzai-re6l3

I am unsure how fix a bug - where if the grouped checkbox field is set as validate - to only have a required message appear under the group of checkboxes - then demand all checkboxes to be required.

Here is the current code base

//renderGroupedCheckboxes

import React from "react";
import { Field } from "redux-form";

import FormControl from "@material-ui/core/FormControl";
import FormLabel from "@material-ui/core/FormLabel";
import FormGroup from "@material-ui/core/FormGroup";
//import FormHelperText from '@material-ui/core/FormHelperText';

import renderCheckboxField from "./renderCheckboxField";

const renderGroupedCheckboxes = (fields) => (
  <FormControl component="fieldset" fullWidth={true}>
    <FormLabel component="legend">{fields.label}</FormLabel>
    <FormGroup row>
      {fields.names.map((item, j) => {
        return (
          <Field
            key={j}
            name={item}
            component={renderCheckboxField}
            label={fields.options[j].label}
            onChange={function (e, newVal) {
              fields.onHandle(e.target.name, newVal);
            }}
          />
        );
      })}
    </FormGroup>
  </FormControl>
);

export default renderGroupedCheckboxes;

the individual checkbox

    //renderCheckboxField
    
    import React from "react";
    import Checkbox from "@material-ui/core/Checkbox";
    import FormControl from "@material-ui/core/FormControl";
    import FormControlLabel from "@material-ui/core/FormControlLabel";
    import FormHelperText from "@material-ui/core/FormHelperText";
    
    const renderCheckboxField = ({
      input,
      rows,
      multiline,
      label,
      meta: { touched, error, warning }
    }) => (
      <FormControl component="fieldset">
        <FormControlLabel
          label={label}
          control={<Checkbox />}
          checked={input.value ? true : false}
          {...input}
        />
        <FormHelperText error={error && error.length > 0 ? true : false}>
          {(error && error.length > 0 ? error : null) ||
            (warning && warning.length > 0 ? warning : null)}
        </FormHelperText>
      </FormControl>
    );

export default renderCheckboxField;
like image 933
The Old County Avatar asked Feb 23 '21 17:02

The Old County


1 Answers

Modify renderGroupedCheckboxes.js. We are checking if any of the checkbox is touched and all the checkboxes are having error, then render the error text

import React from "react";
import { Field } from "redux-form";

import FormControl from "@material-ui/core/FormControl";
import FormLabel from "@material-ui/core/FormLabel";
import FormGroup from "@material-ui/core/FormGroup";
import FormHelperText from "@material-ui/core/FormHelperText";

import renderGroupedCheckboxField from "./renderGroupedCheckboxField";

const renderGroupedCheckboxes = (fields) => {
  let error = null;
  let isAnyFieldTouched = false;
  let isAllFieldsError = true;
  
  for (let name of fields.names) {
    //if touched is true for any one field, isAnyFieldTouched will
    //be true 
    isAnyFieldTouched = isAnyFieldTouched || fields[name].meta.touched;

    if (
      error === null &&
      fields[name].meta.error &&
      fields[name].meta.error.length > 0
    ) {
      error = fields[name].meta.error;
    }

    //if invalid is false for any one field, isAllFieldsError will
    //be false 
    isAllFieldsError = isAllFieldsError && fields[name].meta.invalid;
  }

  return (
    <FormControl component="fieldset" fullWidth={true}>
      <FormLabel component="legend">{fields.label}</FormLabel>
      <FormGroup row>
        {fields.names.map((item, j) => {
          return (
            <Field
              key={j}
              name={item}
              component={renderGroupedCheckboxField}
              label={fields.options[j].label}
              onChange={function (e, newVal) {
                fields.onHandle(e.target.name, newVal);
              }}
            />
          );
        })}
      </FormGroup>
        <FormHelperText error={error && error.length > 0 ? true : false}>
          {isAnyFieldTouched && isAllFieldsError && error && error.length > 0
            ? error
            : null}
        </FormHelperText>
    </FormControl>
  );
};

export default renderGroupedCheckboxes;

Create renderGroupedCheckboxField.js as below. The reason we are creating new file it to not impact current behavior of checkbox field.

import React from "react";
import Checkbox from "@material-ui/core/Checkbox";
import FormControl from "@material-ui/core/FormControl";
import FormControlLabel from "@material-ui/core/FormControlLabel";

const renderGroupedCheckboxField = ({
  input,
  rows,
  multiline,
  label,
  meta: { touched, error, warning }
}) => (
  <FormControl component="fieldset">
    <FormControlLabel
      label={label}
      control={<Checkbox />}
      checked={input.value ? true : false}
      {...input}
    />
  </FormControl>
);

export default renderGroupedCheckboxField;

sandbox - https://codesandbox.io/s/funny-fast-f3i12?file=/src/_SharedFormComponents/renderGroupedCheckboxes.js

like image 106
Ramesh Avatar answered Nov 10 '22 09:11

Ramesh