0
votes

I am new to React, Redux Form and Material. I would like to create a nested drop down selector component that can be dropped in a Redux Form similar to this:

enter image description here

Here is the renderSelectField used to create the select component.

const renderSelectField = ({
  input,
  label,
  meta: { touched, error },
  children,
  ...custom
}) => (
  <SelectField
    floatingLabelText={label}
    errorText={touched && error}
    {...input}
    onChange={(event, index, value) => input.onChange(value)}
    children={children}
    {...custom}
  />
);

const MaterialUiForm = (props) => {
 

  const { handleSubmit, pristine, reset, submitting, classes } = props;
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <Field
          name="favoriteColor"
          component={renderSelectField}
          label="Favorite Color"
        >
          <MenuItem value="ff0000" primaryText="Red" />
          <MenuItem value="00ff00" primaryText="Green" />
          <MenuItem value="0000ff" primaryText="Blue" />
        </Field>
      </div>
      <div>
        <Field
          id='chapter'
           name='chapter'
           component={SelectMenu}
           label='Chapter'
        />
      </div>
      <div>
        <button type="submit" disabled={pristine || submitting}>
          Submit
        </button>
        <button type="button" disabled={pristine || submitting} onClick={reset}>
          Clear Values
        </button>
      </div>
    </form>
  );
};

My SelectMenu component is

    const chapterFormValues = [
  {
    key: "international-4",
    caption: "France"
  },
  {
    key: "international-5",
    caption: "Africa"
  },
  {
    key: "international-6",
    caption: "United Kingdom"
  },
  {
    key: "usa-key",
    caption: "North America",
    subMenuItems: [
      {
        key: "usaChapter-1",
        caption: "Central"
      },
      {
        key: "usaChapter-2",
        caption: "East"
      }
    ]
  }
];

const SelectMenu = (props) => {

  const [open, setOpen] = useState(false);

  const handleClick = () => {
    setOpen((open) => !open);
  };

  const handleSubMenuClose = () => {
    setOpen((open) => !open);
  };

  const { label, classes } = props;
  const renderMenuItems = () => {
    return (
      chapterFormValues !== undefined &&
      chapterFormValues.map((option) => {
        if (option.hasOwnProperty("subMenuItems")) {
          return (
            <React.Fragment>
              <MenuItem onClick={handleClick} className={classes.menuItem}>
                {option.caption}
                {open ? <IconExpandLess /> : <IconExpandMore />}
              </MenuItem>

              <Collapse in={open} timeout="auto" unmountOnExit>
                <hr />
                {option.subMenuItems.map((item) => (
                  <MenuItem
                    key={item.key}
                    className={classes.subMenuItem}
                    onClick={handleSubMenuClose}
                  >
                    {item.caption}
                  </MenuItem>
                ))}
              </Collapse>
            </React.Fragment>
          );
        }
        return (
          <MenuItem
            className={classes.menuItem}
            key={option.key}
            value={option.caption === "None" ? "" : option.caption}
          >
            {option.caption}
          </MenuItem>
        );
      })
    );
  };

  return (
    <FormControl>
      <InputLabel>{label}</InputLabel>
      <MuiSelect
        input={<Input id={`${props.id}-select`} />}
        value={props.value}
        {...props.input}
        {...props.custom}
      >
        {renderMenuItems()}
      </MuiSelect>
    </FormControl>
  );
};

Here is a link to the code sandbox I created. Material UI ReduxForm Select

It works except the nested drop down does not update the selector field. I have researched this and found this issue Stackoverflow redux form with nested lists but no solution.

Can anyone give me advice as to what I am missing? I believe I need to pass the event in the handleSubMenuClose function back to the Redux Form somehow but am stumped as to how to do this.

1

1 Answers

0
votes

Well using Material UI MenuItem didn't work but I was able to use redux form and create a nested drop down that did. This is a screen shot of what I created. It did not have the functionality to open/close a panel but it still gave the user a sense of a nested dropdown.

Here is the code that I changed in the SelectMenu method. The key was to use the native form of the Material UI Select component and the optgroup element.

const SelectMenu = (props) => {
  

  const { label, classes } = props;
  const renderMenuItems = () => {
    return (
      chapterFormValues !== undefined &&
      chapterFormValues.map((option) => {
        if (option.hasOwnProperty("subMenuItems")) {
          return (
            <React.Fragment>
              <optgroup  label={option.caption} className={classes.menuItem}>
                
                {option.subMenuItems.map((item) => (
                  <option
                    key={item.key}
                    className={classes.subMenuItem}
                  >
                    {item.caption}
                  </option>
             
                ))}
            </optgroup>
            </React.Fragment>
          );
        }
        return (
          <option
            className={classes.menuItem}
            key={option.key}
            value={option.caption === "None" ? "" : option.caption}
          >
            {option.caption === "None" ? "" : option.caption}
          </option>
        );
      })
    );
  };

  return (
    <FormControl>
      <InputLabel>{label}</InputLabel>
      <Select
        native
        input={<Input id={`${props.id}-select`} />}
        value={props.value}
        {...props.input}
        {...props.custom}
      >
        {renderMenuItems()}
      </Select>
    </FormControl>
  );
};

Helpfully links were :

HTML / CSS: Nested <options> in a <select> field?

Redux Form Material UI: Select with Nested Lists not working