Retrieving value from <select> with multiple option in React

JavascriptDomReactjs

Javascript Problem Overview


The React way to set which option is selected for a select box, is to set a special value prop on the <select> itself, corresponding to the value attribute on the <option> element you desire to be selected. For a multiple select this prop can accept an array instead.

Now because this is a special attribute, I'm wondering what the canonical way is to retrieve the selected options in the same array-of-option-values-structure when the user changes things (so I can pass it through a callback to a parent component etc), since presumably the same value property won't be available on the DOM element.

To use an example, with a text field you would do something like this (JSX):

var TextComponent = React.createClass({
  handleChange: function(e) {
    var newText = e.target.value;
    this.props.someCallbackFromParent(newText);
  },
  render: function() {
    return <input type="text" value={this.props.someText} onChange={this.handleChange} />;
  }
});

What is the equivalent to replace ??? for this multiple select component?

var MultiSelectComponent = React.createClass({
  handleChange: function(e) {
    var newArrayOfSelectedOptionValues = ???;
    this.props.someCallbackFromParent(newArrayOfSelectedOptionValues);
  },
  render: function() {
    return (
      <select multiple={true} value={this.props.arrayOfOptionValues} onChange={this.handleChange}>
        <option value={1}>First option</option>
        <option value={2}>Second option</option>
        <option value={3}>Third option</option>
      </select>
    );
  }
});

Javascript Solutions


Solution 1 - Javascript

The same way you do anywhere else, since you're working with the real DOM node as the target of the change event:

handleChange: function(e) {
  var options = e.target.options;
  var value = [];
  for (var i = 0, l = options.length; i < l; i++) {
    if (options[i].selected) {
      value.push(options[i].value);
    }
  }
  this.props.someCallback(value);
}

Solution 2 - Javascript

With Array.from() and e.target.selectedOptions you can perform a controlled select-multiple:

handleChange = (e) => {
  let value = Array.from(e.target.selectedOptions, option => option.value);
  this.setState({values: value});
}

target.selectedOptions return a HTMLCollection

https://codepen.io/papawa/pen/XExeZY

Solution 3 - Javascript

Easiest way...

handleChange(evt) {
  this.setState({multiValue: [...evt.target.selectedOptions].map(o => o.value)}); 
}

Solution 4 - Javascript

In case you want to use ref you can get selected values like this:

var select = React.findDOMNode(this.refs.selectRef); 
var values = [].filter.call(select.options, function (o) {
      return o.selected;
    }).map(function (o) {
      return o.value;
    });

2018 ES6 update

  let select = this.refs.selectRef;
  let values = [].filter.call(select.options, o => o.selected).map(o => o.value);

Solution 5 - Javascript

In the case you would like to keep track of the selected options while the form is being completed:

handleChange(e) {
    // assuming you initialized the default state to hold selected values
    this.setState({
        selected:[].slice.call(e.target.selectedOptions).map(o => {
            return o.value;
        });
    });
}

selectedOptions is an array-like collection/list of elements related to the DOM. You get access to it in the event target object when selecting option values. Array.prototype.sliceand call allows us to create a copy of it for the new state. You could also access the values this way using a ref (in case you aren't capturing the event), which was another answer for the question.

Solution 6 - Javascript

You can actually find the selectedOptions inside the target... no need to iterate over all the options. Let's imagine you want to send the values to an onChange function passed to your component as props: you can use the following function on the onChange of your multiple select.

onSelectChange = (e) => {
    const values = [...e.target.selectedOptions].map(opt => opt.value);
    this.props.onChange(values);
  };

Solution 7 - Javascript

The following worked for me

var selectBoxObj = React.findDOMNode(this.refs.selectBox)
var values = $(selectBoxObj).val()

Solution 8 - Javascript

Another way to do it:

handleChange({ target }) {
    this.props.someCallback(
       Array.prototype.slice.call(target.selectedOptions).map(o => o.value)
    )
}

Solution 9 - Javascript

Try this one:

dropdownChanged = (event) => {
    let obj = JSON.parse(event.target.value);
    this.setState(
        {
            key: obj.key,
            selectedName: obj.name,
            type: obj.type
        });
}


<select onChange={this.dropdownChanged} >
<option value={JSON.stringify({ name: 'name', key: 'key', type: "ALL" })} >All Projetcs and Spaces</option></select>

Solution 10 - Javascript

After spending a lot of time with this topic, and seeing that we are now all using mostly hooks and newbies may have never even dealt with classes in reactjs. I decided to update this answer so that people can easily deal with

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionInklingView Question on Stackoverflow
Solution 1 - JavascriptJonny BuchananView Answer on Stackoverflow
Solution 2 - JavascriptMendesView Answer on Stackoverflow
Solution 3 - JavascriptjamesmfriedmanView Answer on Stackoverflow
Solution 4 - JavascriptMax PodriezovView Answer on Stackoverflow
Solution 5 - JavascriptrambossaView Answer on Stackoverflow
Solution 6 - JavascriptLanciView Answer on Stackoverflow
Solution 7 - JavascriptmantishView Answer on Stackoverflow
Solution 8 - JavascriptAral RocaView Answer on Stackoverflow
Solution 9 - JavascriptSlavi VatahovView Answer on Stackoverflow
Solution 10 - JavascriptJulio SpinelliView Answer on Stackoverflow