Search code examples
reactjsreactjs.net

reactjs get select values - always undefined


I'm quite new to reactjs, so I wrote a fairly simple page to test a 'dynamic' <select> options and how to get the selected value. What I wanted to do was on submit, be able to get the selected values by iterating through the this.refs but I'm getting undefined values. I'm not sure how to make it work in a controlled manner using the handle change so I opted to go the uncontrolled approach. However I'd like to know how to do it both ways. Or is there a neater/preferred way to get the selected values on form submit?

Also in the rendering of the select, why can't I add a ref={this.props.formId} there instead of on the OptionsList? If i remove the ref on OptionsList and have it in the select then it doesn't recognise any select inputs.

var data1 = [
  { Id: 1, Name: "Option 1", Value: "Value 1" },
  { Id: 2, Name: "Option 2", Value: "Value 2" },
  { Id: 3, Name: "Option 3", Value: "Value 3" }
];

var data2 = [
  { Id: 4, Name: "Option 4", Value: "Value 4" },
  { Id: 5, Name: "Option 5", Value: "Value 5" },
  { Id: 6, Name: "Option 6", Value: "Value 6" }
];

var FormOptionList = React.createClass({
    handleSubmit: function (e) {
        e.preventDefault();

        for (var ref in this.refs) {
            console.log(this.refs[ref].value);
        }

        return;
    },
    render: function () {
        return (
          <div className="formList">
              <form onSubmit={this.handleSubmit}>
                  <div>
                    <OptionsList key="ListA" formId="ListA" options={this.props.data1} ref="ListA" />
                    <br />
                    <OptionsList key="ListB" formId="ListB" options={this.props.data2} ref="ListB" />
                  </div>
                  <input type="submit" value="Post" />
              </form>
          </div>
      );
    }
});

var OptionsList = React.createClass({
    //getInitialState: function () {
    //    return {
    //        options: [],
    //        selectValue: 'Option 1'
    //    };
    //},
    //handleChange: function(e) {
    //    this.setState({ selectValue: e.target.value })
    //},
    getInitialState: function () {
        return {
            options: []
        };
    },
    render: function () {
        var optionsList = this.props.options.map(function (option) {
            return (
                <option key={option.Id} value={option.Value}>{option.Name}</option>
            )
        });
        return (
            <select>
                {optionsList}
            </select>
        );
    }
});

ReactDOM.render(
  <FormOptionList data1={data1} data2={data2} />,
  document.getElementById('content')
);

Solution

  • Using refs is not the best way to achieve what you want.

    A good way would be

    1º Add a method in your parent component to store the values of your <OptionList> components

    handleSelectChange(select,value){
        this.setState({[select] : value})
    }
    

    2º Pass handleSelectChange to <OptionList> as a prop

    <OptionsList key="ListA"
         formId="ListA" options={this.props.data1}
         onChange={this.handleSelectChange} />
    

    3º Pass the <select> value to the parent component using onChange + handleSelectChange

    var OptionsList = React.createClass({
        render: function () {
            var optionsList = this.props.options.map((option) => {
                return (
                    <option key={option.Id} value={option.Value}>{option.Name}</option>
                )
            });
            return (
                <select onChange={(e) => this.props.onChange(this.props.formId,e.target.value)}>
                    {optionsList}
                </select>
            );
        }
    });
    

    full working example