How do I get the value in the parent from a child components <select> in ReactJS onSubmit()
<p>I am having an issue trying to get the value from a <code>&lt;select&gt;</code>.  The component which renders it is <code>DualListBox</code> which should add a <code>ref</code> of <code>selected</code> to the <code>&lt;select&gt;</code> tag.</p>

<pre><code>&lt;div className="rdl-selected"&gt;
          &lt;select className="form-control" name={this.props.name} ref="selected" multiple&gt;
            {selected}
          &lt;/select&gt;
        &lt;/div&gt;
</code></pre>

<p>The problem is that in the parent component of <code>UpdateDialog</code> I am unable to get the value for the DOM when I click save on the page in the <code>handleSubmit</code> </p>

<pre><code>ReactDOM.findDOMNode(this.refs['selected']).value.trim();
</code></pre>

<p><strong>Question:</strong></p>

<p>What am I missing?  I'm wondering if the component needs to be wrapped with something to return the value correctly.</p>

<p><strong>Update</strong>
Added changes as noted by @Klassman for passing onChange and it works</p>

<p>This way the passed down onChange is called with the state value.  Thank You</p>

<p>** Is there another way to do this not passing the value within the state?**
** Why was I unable to reference it by the ref?**</p>

<p>Thank you</p>

<p><strong>Code</strong></p>

<p><strong>UpdateDialog</strong></p>

<pre><code>'use strict';

const React = require('react');
const ReactDOM = require('react-dom');

const when = require('when');
const client = require('./client');
const follow = require('./follow'); // function to hop multiple links by "rel"


const ListBoxWidget = require('./ListBoxWidget');

const root = '/api';

class UpdateDialog extends React.Component {

  constructor(props) {
    super(props);
    this.state = {selectedListObjects: null, unselectedListObjects: null};
    this.handleSubmit = this.handleSubmit.bind(this);
    this.onChange = this.onChange.bind(this);
    this.setupTestSuite = this.setupTestSuite.bind(this);
  }

  onChange(selected) {
    this.setState({ selected });
  }

  handleSubmit(e) {
    e.preventDefault();
    var updatedObject = {};
    this.props.attributes.forEach(attribute =&gt; {
      var rd = ReactDOM.findDOMNode(this.refs[attribute]).value.trim();
      console.log("rd for attribute " + attribute);
      console.log(this.refs[attribute]);
      console.log(rd);
      updatedObject[attribute] = rd;
    });


      console.log("going into test suite ");
      console.log(this.props.objectName);

    // save the list box value for the test cases
    if (this.props.objectName == "Test Suite") {
      console.log("going into test suite ");
      console.log("this.refs['selected']");
      console.log(this.refs.selected);
      console.log(this.refs.available);

      console.log("this.state.selected");
      console.log(this.state.selected);
      console.log("?");
      var selectedTestCases = ReactDOM.findDOMNode(this.refs['selected']).value.trim();
      console.log("selected react dom");
      console.log(selectedTestCases);
      if (selectedTestCases != null) {
        console.log("selected react dom . value");
        console.log(selectedTestCases.value);
      }

    }
    this.props.onUpdate(this.props.object, updatedObject);
    window.location = "#";
  }

  componentDidMount() {
    console.log("calling componentDidMount in update");

    if (this.props.objectName == "Test Suite") {
      this.setupTestSuite();
    }
  }

  render() {
    var inputs = this.props.attributes.map(attribute =&gt;
        &lt;p key={attribute}&gt;
          &lt;input type="text" placeholder={attribute}
               defaultValue={this.props.object.entity[attribute]}
               ref={attribute} className="field" /&gt;
        &lt;/p&gt;
    );

    var dialogId = "updateObject-" + this.props.object.entity._links.self.href;

    return (
      &lt;div&gt;
        &lt;a href={"#" + dialogId}&gt;Update&lt;/a&gt;

        &lt;div id={dialogId} className="modalDialog"&gt;
          &lt;div&gt;
            &lt;a href="#" title="Close" className="close"&gt;X&lt;/a&gt;

            &lt;h2&gt;Update an {this.props.objectName}&lt;/h2&gt;

            &lt;form&gt;
              {inputs}
              {this.props.objectName == "Test Suite" &amp;&amp; this.state.selectedListObjects != null &amp;&amp; this.state.unselectedListObjects != null &amp;&amp;
                &lt;ListBoxWidget
                  onChange={this.onChange}
                  refName='selectedTestCasesRef'
                  name='selectedTestCases'
                  unselectedListObjects={this.state.unselectedListObjects}
                  selectedListObjects={this.state.selectedListObjects} /&gt;
              }
              &lt;button onClick={this.handleSubmit}&gt;Update&lt;/button&gt;
            &lt;/form&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    )
  }

}

module.exports = UpdateDialog
</code></pre>

<p><strong>ListBoxWidget</strong></p>

<pre><code>    'use strict';

const React = require('react');

// import components
const DualListBox = require('react-dual-listbox');

class ListBoxWidget extends React.Component {
    constructor(props) {
        super(props);
        this.state = { selected: this.props.selectedListObjects };
        this.onChange = this.onChange.bind(this);
    }

    onChange(selected) {
        this.setState({ selected });
        this.props.onChange(selected);
    }

    render() {

        return (
          &lt;DualListBox
            name={this.props.name}
            options={this.props.unselectedListObjects}
            preserveSelectOrder
            selected={this.state.selected}
            defaultValue={this.props.selectedListObjects}
            onChange={this.onChange} /&gt;

        )
    }
}

module.exports = ListBoxWidget
</code></pre>

<p><strong>Package.json</strong></p>

<pre><code>"babel-core": "^6.0.0",
"babel-loader": "^6.0.0",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"react": "^15.0.1",
"react-dom": "^15.0.1",
"rest": "^1.3.2",
"sockjs-client": "^1.0.3",
"stompjs": "^2.3.3",
"webpack": "^1.13.0",
"when": "^3.7.7",
"react-bootstrap": "^0.29.3",
"jquery":  "^2.2.3",
"react-dual-listbox":  "^0.3.3"
</code></pre>

<p>Here is the class from react-dual-listbox</p>

<p><strong>DualListBox</strong></p>

<pre><code>import React from 'react';

import Action from './Action';

class DualListBox extends React.Component {
  static propTypes = {
    name: React.PropTypes.string,
    options: React.PropTypes.array,
    available: React.PropTypes.array,
    selected: React.PropTypes.array,
    onChange: React.PropTypes.func,
    preserveSelectOrder: React.PropTypes.bool,
  };

  /**
   * @param {Object} props
   *
   * @returns {void}
   */
  constructor(props) {
    super(props);

    this.onClick = this.onClick.bind(this);
    this.onDoubleClick = this.onDoubleClick.bind(this);
  }

  /**
   * @param {Object} event
   *
   * @return {void}
   */
  onClick(event) {
    const { target } = event;
    const { options, onChange } = this.props;
    const direction = target.dataset.moveDirection;
    const isMoveAll = target.dataset.moveAll;
    const selectRef = direction === 'right' ? 'available' : 'selected';

    let selected = [];

    if (isMoveAll === '1') {
      selected = direction === 'right' ? this.makeOptionsSelected(options) : [];
    } else {
      selected = this.toggleSelected(
        this.getSelectedOptions(this.refs[selectRef])
      );
    }

    onChange(selected);
  }

  /**
   * @param {Object} event
   *
   * @returns {void}
   */
  onDoubleClick(event) {
    const value = event.target.value;
    const selected = this.toggleSelected([value]);

    this.props.onChange(selected);
  }

  /**
   * Converts a flat array to a key/value mapping.
   *
   * @param {Array} options
   *
   * @returns {Object}
   */
  getLabelMap(options) {
    let labelMap = {};

    options.forEach((option) =&gt; {
      if (option.options !== undefined) {
        labelMap = { ...labelMap, ...this.getLabelMap(option.options) };
      } else {
        labelMap[option.value] = option.label;
      }
    });

    return labelMap;
  }

  /**
   * Returns the selected options from a given element.
   *
   * @param {Object} element
   *
   * @returns {Array}
   */
  getSelectedOptions(element) {
    return [...element.options]
      .filter((option) =&gt; option.selected)
      .map((option) =&gt; option.value);
  }

  /**
   * Make all the given options selected.
   *
   * @param {Array} options
   *
   * @returns {Array}
   */
  makeOptionsSelected(options) {
    let selected = [];

    this.filterAvailable(options).forEach((option) =&gt; {
      if (option.options !== undefined) {
        selected = [...selected, ...this.makeOptionsSelected(option.options)];
      } else {
        selected.push(option.value);
      }
    });

    return [...this.props.selected, ...selected];
  }

  /**
   * Toggle a new set of selected elements.
   *
   * @param {Array} selected
   *
   * @returns {Array}
   */
  toggleSelected(selected) {
    const oldSelected = this.props.selected.slice(0);

    selected.forEach((value) =&gt; {
      const index = oldSelected.indexOf(value);

      if (index &gt;= 0) {
        oldSelected.splice(index, 1);
      } else {
        oldSelected.push(value);
      }
    });

    return oldSelected;
  }

  /**
   * Filter options by a filtering function.
   *
   * @param {Array} options
   * @param {Function} filterer
   *
   * @returns {Array}
   */
  filterOptions(options, filterer) {
    const filtered = [];

    options.forEach((option) =&gt; {
      if (option.options !== undefined) {
        const children = this.filterOptions(option.options, filterer);

        if (children.length &gt; 0) {
          filtered.push({
            label: option.label,
            options: children,
          });
        }
      } else if (filterer(option)) {
        filtered.push(option);
      }
    });

    return filtered;
  }

  /**
   * Filter the available options.
   *
   * @param {Array} options
   *
   * @returns {Array}
   */
  filterAvailable(options) {
    if (this.props.available !== undefined) {
      return this.filterOptions(options, (option) =&gt;
        this.props.available.indexOf(option.value) &gt;= 0 &amp;&amp;
        this.props.selected.indexOf(option.value) &lt; 0
      );
    }

    // Show all un-selected options
    return this.filterOptions(options, (option) =&gt;
      this.props.selected.indexOf(option.value) &lt; 0
    );
  }

  /**
   * Filter the selected options.
   *
   * @param {Array} options
   *
   * @returns {Array}
   */
  filterSelected(options) {
    if (this.props.preserveSelectOrder) {
      return this.filterSelectedByOrder(options);
    }

    // Order the selections by the default order
    return this.filterOptions(options, (option) =&gt;
      this.props.selected.indexOf(option.value) &gt;= 0
    );
  }

  /**
   * Preserve the selection order. This drops the opt-group associations.
   *
   * @param {Array} options
   *
   * @returns {Array}
   */
  filterSelectedByOrder(options) {
    const labelMap = this.getLabelMap(options);

    return this.props.selected.map((selected) =&gt; ({
      value: selected,
      label: labelMap[selected],
    }));
  }

  /**
   * @returns {Array}
   */
  renderOptions(options) {
    return options.map((option, index) =&gt; {
      if (option.options !== undefined) {
        return (
          &lt;optgroup key={index} label={option.label}&gt;
            {this.renderOptions(option.options)}
          &lt;/optgroup&gt;
        );
      }

      return (
        &lt;option key={index} value={option.value} onDoubleClick={this.onDoubleClick}&gt;
          {option.label}
        &lt;/option&gt;
      );
    });
  }

  /**
   * @returns {React.Component}
   */
  render() {
    const { options } = this.props;
    const available = this.renderOptions(this.filterAvailable(options));
    const selected = this.renderOptions(this.filterSelected(options));

    return (
      &lt;div className="react-dual-listbox"&gt;
        &lt;div className="rdl-available"&gt;
          &lt;select className="form-control" ref="available" multiple&gt;
            {available}
          &lt;/select&gt;
        &lt;/div&gt;
        &lt;div className="rdl-actions"&gt;
          &lt;div className="rdl-actions-right"&gt;
            &lt;Action direction="right" isMoveAll onClick={this.onClick} /&gt;
            &lt;Action direction="right" onClick={this.onClick} /&gt;
          &lt;/div&gt;
          &lt;div className="rdl-actions-left"&gt;
            &lt;Action direction="left" onClick={this.onClick} /&gt;
            &lt;Action direction="left" isMoveAll onClick={this.onClick} /&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div className="rdl-selected"&gt;
          &lt;select className="form-control" name={this.props.name} ref="selected" multiple&gt;
            {selected}
          &lt;/select&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    );
  }
}

export default DualListBox;
</code></pre>