Option value is not appearing when selected in drop down box

I am trying to troubleshoot a problem which I am unable to solve. The issue is that I have a dropdown box with a select tag with some menu items in it. When I click one of the menu items the value is not appearing in the select box and its just empty. However when I console log the selected item I can see what I am selecting which is the menu item. Heres the code:

<Select labelId="demo-simple-select-label" id="demo-simple-select" value={selectedMake} onChange={handleMake}>
              {console.log(makes)}
              {makes &&
                makes.map((select, key) => (
                  <MenuItem key={key} value={select}>
                      {console.log(select)}
                    {select.name}
                  </MenuItem>
                ))}
            </Select>

If you're wondering what is "makes", it is just this:

(3) [{…}, {…}, {…}]
0: {name: "Honda", id: "5de9c553bce4b703a335c204"}
1: {name: "Toyota", id: "5e4dfbee2d445b7525414c1f"}
2: {name: "Suzuki", id: "5e4e00732d445b7525414c46"}

Im not sure why the when Honda is selected for example it is not showing in the box. I reckon it might be something to do with the id. Do let me know how to solve this problem.

This is the handleMake function as well, it is a function that is passed in as a prop from another file:

handleMake = (event) => {
    this.setState({
      selectedMake: event.target.value.name,
      selectedMakeId: event.target.value.id,
    });
  };

Upvotes: 1

Views: 5567

Answers (1)

Drew Reese
Drew Reese

Reputation: 202605

Issue

Objects cannot be the value of a select option, it must be a non-object value. In your you are setting the option value to the entire "makeobject, but setting theSelectvalue to *just* the make'sname` property, which will never match.

handleMake = (event) => {
  this.setState({
    selectedMake: event.target.value.name, // <-- make's name
    selectedMakeId: event.target.value.id,
  });
};

...

<Select
  labelId="demo-simple-select-label"
  id="demo-simple-select"
  value={selectedMake} // <-- only a make's name
  onChange={handleMake}
>
  {makes.map((select, key) => (
    <MenuItem key={key} value={select}> // <-- entire make object!
      {select.name}
    </MenuItem>
  ))}
</Select>

Solution

I suggest storing the selected index or id in state instead.

There is no need to duplicate so much data into state as you can easily derive the car make and id from a stored array index or search using the id. If you used data from one of the make objects then you'd need to search the makes array each time (O(n) linear time) to find a match, but by using the index you can get just the make object needed in O(1) constant time.

handleMake = (event) => {
  this.setState({
    selectedMake: event.target.value,
  });
};

...

<Select
  labelId="demo-simple-select-label"
  id="demo-simple-select"
  value={this.state.selectedMake} // <-- value is "index"
  onChange={this.handleMake}
>
  {makes.map((make, index) => (
    <MenuItem key={index} value={index}> // <-- pass index as "value"
      {make.name}
    </MenuItem>
  ))}
</Select>

To handle using the selectedMake, for example, if selectedMake === 0:

makes[selectedMake] // { name: "Honda", id: "5de9c553bce4b703a335c204"}

Example Component

Edit option-value-is-not-appearing-when-selected-in-drop-down-box

function App() {
  const [selectedMake, setSelectedMake] = useState(-1);

  const changeHandler = (e) => setSelectedMake(e.target.value);

  useEffect(() => {
    console.log(selectedMake, makes[selectedMake]);
  }, [selectedMake]);

  return (
    <div className="App">
      <select value={selectedMake} onChange={changeHandler}>
        <option disabled value={-1}>
          Make
        </option>
        {makes.map((make, i) => (
          <option key={make.id} value={i}>
            {make.name}
          </option>
        ))}
      </select>
    </div>
  );
}

Upvotes: 1

Related Questions