ReactJs: Cannot select item from MenuItem

Viewed 23

I have a case where the I have 3 items, and at in the case where is the first item, it should be displaying only the first item, and not allow the user to select 2nd and 3rd, but in case wher isItFirt = false then the user should be able to choose from the list. I wrote the minimal reproducible example as shown below:

import * as React from "react";
import {
  Typography,
  Button,
  Dialog,
  Box,
  Select,
  InputLabel,
  FormControl,
  MenuItem,
  SelectChangeEvent
} from "@mui/material";

enum MyOptions {
  FIRST = 1,
  SECOND = 2,
  THIRD = 3
}

export default function App() {
  const [open, setOpen] = React.useState(true);
  const [myOptions, setMyOptions] = React.useState(MyOptions.SECOND as number);
  const handleChange = (event: SelectChangeEvent) => {
    let nr = parseInt(event.target.value, 10);
    setMyOptions(nr);
  };

  const isItFirst: boolean = false;

  const handleClose = () => {
    setOpen(false);
  };

  const somethingHappens = () => {
    console.log("clicked: ", myOptions);
    setOpen(false);
  };

  React.useEffect(() => {
    if (isItFirst) {
      setMyOptions(MyOptions.FIRST as number);
    }
  }, [isItFirst]);

  return (
    <div>
      <Button
        variant="contained"
        size="small"
        onClick={() => {
          setOpen(true);
        }}
      >
        Display dialog
      </Button>
      <Dialog
        open={open}
        onClose={handleClose}
        aria-labelledby="modal-modal-title"
        aria-describedby="modal-modal-description"
      >
        <Box>
          <Typography id="modal-modal-title" variant="h6" component="h4">
            Select one of the options
          </Typography>
          <FormControl>
            <InputLabel id="1">Options</InputLabel>
            <Select
              labelId=""
              id=""
              value={myOptions}
              label="Options"
              onChange={(e: any) => handleChange(e)}
            >
              {isItFirst ? (
                <MenuItem value={MyOptions.FIRST}>This is first</MenuItem>
              ) : (
                <div>
                  <MenuItem value={MyOptions.SECOND} key={MyOptions.SECOND}>
                    This is second
                  </MenuItem>
                  <MenuItem value={MyOptions.THIRD} key={MyOptions.THIRD}>
                    This is third
                  </MenuItem>
                </div>
              )}
            </Select>
          </FormControl>
        </Box>
        <Button
          variant="contained"
          size="small"
          onClick={() => {
            somethingHappens();
          }}
        >
          Select
        </Button>
      </Dialog>
    </div>
  );
}

This is the error output:

MUI: You have provided an out-of-range value `1` for the select component.
Consider providing a value that matches one of the available options or ''.
The available values are "". 

And this is the dialog box that is shown in the case when isItFirst === false, I do not understand why it is shown as blank when I set the state of myOptions with the help of useEffect. enter image description here

1 Answers

According to this document for children prop of Select

The option elements to populate the select with. Can be some MenuItem when native is false and option when native is true. ⚠️The MenuItem elements must be direct descendants when native is false.

So technically, we cannot pass div or any other elements to wrap MenuItem.

For the fix, you can consider to use filter and map with a pre-defined option like below

const options: {value: MyOptions, label: string}[] = [
  {value: MyOptions.FIRST, label: "This is first"},
  {value: MyOptions.SECOND, label: "This is second"},
  {value: MyOptions.THIRD, label: "This is thrid"}
]

Here is how we apply options to Select

<Select
  labelId=""
  id=""
  value={myOptions}
  label="Options"
  onChange={handleChange}
  key="first-select"
>
  {options
    .filter((option) =>
      isItFirst
        ? option.value === MyOptions.FIRST
        : option.value !== MyOptions.FIRST
    )
    .map((option) => (
      <MenuItem key={option.value} value={option.value}>
        {option.label}
      </MenuItem>
    ))}
</Select>
Related