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:
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.
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