37

So I'm trying to get a select element's value in reactjs, but just can't figure it out. The this.refs.selectElement.getDOMNode().value is always coming as undefined. All other controls on the form like text are working fine. Any ideas? Is it that you can't get the value of select element via refs and must use onChange event?

Updated:

var TestSelectClass = React.createClass({
  mixins: [Router.Navigation],

  _handleDube: function(event) {
    DubeActionCreators.DubeTest({
      message: this.refs.message.getDOMNode().value,
      tax: this.refs.tax.getDOMNode().value,
      validity: this.refs.valid_for.getDOMNode().value
    });
  },

  render: function() {
    return (
      <ReactBootstrap.ListGroup>
          <textarea
            className="form-control"
            rows="3"
            placeholder="Enter message"
            ref="message" >
          </textarea>
          <div className="input-group">
            <span className="input-group-addon" id="basic-addon1">$</span>
            <input type="text" className="form-control" placeholder="10" aria-describedby="basic-addon1" ref="tax" />
          </div>
        <Input type="select" value="1" ref="valid_for">
          <option value="1">1 hour</option>
          <option value="2">1 day</option>
          <option value="2">5 days</option>
        </Input>
      </ReactBootstrap.ListGroup>
    )
  }
});

Updated: Solution So, if anyone runs into something similar, apparently if you are using react-bootstrap you can't get to the Input element if you have wrapped it in a ListGroup. Either take it out from it or wrap all Input elements in a <form> tag. This solved my issue, thanks for all the help.

7
  • 1
    Can you post your code? Commented Feb 23, 2015 at 16:34
  • I've updated it with the code. Commented Feb 23, 2015 at 16:42
  • You nowhere set ref="selectElement". Commented Feb 23, 2015 at 17:22
  • @julen That was just as an example. Please look at the code, I do set ref="valid_for" and then access it via this.refs.valid_for.getDOMNode().value Commented Feb 23, 2015 at 18:54
  • Why are you using "Input" instead of "select"? Commented Feb 23, 2015 at 19:26

10 Answers 10

51

it's quite simple:

on the render method you should keep an eye on the bind(this)

<select onChange={this.yourChangeHandler.bind(this)}>
  <option value="-1" disabled>--</option>
  <option value="1">one</option>
  <option value="2">two</option>
  <option value="3">three</option>
</select>

and your handler is like:

yourChangeHandler(event){
  alert(event.target.value)
}
Sign up to request clarification or add additional context in comments.

2 Comments

This is the best way of doing that.
For performance reasons, best to bind your callback in your component's constructor vs. inline like this. Per the docs.
31

I see you are using react-bootstrap, which includes a wrapper around regular input elements.

In this case you need to use the getInputDOMNode() wrapper function in order to get the underlying input's actual DOM element. But you can also use the getValue() convenience function that react-bootstrap provides for Input elements.

So your _handleDube function should look like:

  _handleDube: function(event) {
    DubeActionCreators.DubeTest({
      message: this.refs.message.getInputDOMNode().value,
      tax: this.refs.tax.getInputDOMNode().value,
      validity: this.refs.valid_for.getValue()
    });
  },

See this JSFiddle for a complete example: http://jsfiddle.net/mnhm5j3g/1/

9 Comments

Doesn't work. The getInputDOMNode() is coming up as undefined.
It does work, I have added a JSFiddle to showcase an example.
You are right, it does work. However, for some reason it doesn't work in my app, I'm going to accept the answer as it's the correct one though. Thanks
The API changed in React, now the getDOMNode() above should read something like React.findDOMNode(this.refs.message).value.
In React 15.2.1 this.refs.message.value seems to read the value.
|
16

Make a function handleChange(). Then, put it in your render() like this:

<Input type="select" value="1" ref="valid_for" onChange={this.handleChange}>

And the function in the component:

handleChange: function(e) {
  var val = e.target.value;
},

1 Comment

Yeah, that's what I'm doing right now, but the question is can't we use refs at all for a select element?
6
"react": "^15.0.2",
"react-bootstrap": "^0.29.3",
"react-dom": "^15.0.2",

under the env, ReactDOM.findDOMNode() works for me.

in render():

<FormControl name="username" ref="username"/>

in handler():

const username = findDOMNode(this.refs.username);

Comments

4

None of the above worked for me. I actually had to go through the DOM hierarchy to come up with a way to extract the value. PS: I did not use ReactBootstrap.ListGroup in my code. Just the Input from React Bootstrap. Here is my code (ES6+).

import ReactDOM from 'react-dom';

getValueFromSelect(ref){
    var divDOMNode = ReactDOM.findDOMNode(ref);
    /* the children in my case were a label and the select itself. 
       lastChild would point to the select child node*/
    var selectNode = divDOMNode.lastChild;
    return selectNode.options[selectNode.selectedIndex].text;
}

Dependencies:

    "react": "^0.14.3",
    "react-bootstrap": "0.28.1",
    "react-dom": "^0.14.3",

Comments

1

Refs as strings are considered legacy and may be deprecated. But it seems as if react-bootstrap components won't work with callback refs. I was working on this today to handle a search input.

class SearchBox extends Component {
  constructor(props, context) {
    super(props, context);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange() {
    this.props.updateQuery(this._query.value);
  }

  render() {
    // ...
    <FormControl
      onChange={this.handleChange}
      ref={(c) => this._query = c} // should work but doesn't
      value={this.props.query}
      type="text"
      placeholder="Search" />
    // ...
  }
}

I wound up grabbing the change event and getting the value from it. This doesn't feel the "React way" or very current, but it works.

class SearchBox extends Component {
  constructor(props, context) {
    super(props, context);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.props.updateQuery(e.target.value);
  }

  render() {
    // ...
    <FormControl
      onChange={this.handleChange}
      value={this.props.query}
      type="text"
      placeholder="Search" />
    // ...
  }
}

Comments

1

There is yet another easy way! if you use <FormGroup> component and set the controlId props, the inner DOM (<input>, ...) will get that controlId as its id attribute. for example:

<FormGroup controlId="myInputID">
  <ControlLabel>Text</ControlLabel>
  <FormControl type="text" placeholder="Enter text" />
</FormGroup>

Then you will have the value by calling document.getElementById:

var myInputValue = document.getElementById("myInputID").value;

Comments

1

If you are here like me using the latest FormControl component here's a solution I did:

import React, {Component} from 'react'
import ReactDOM from 'react-dom'

class Blah extends Component {
    getSelectValue = () => {
        /* Here's the key solution */
        console.log(ReactDOM.findDOMNode(this.select).value)
    }

    render() {
        return
        <div> 
            <FormControl
            ref={select => { this.select = select }}
            componentClass="select"
            disabled={this.state.added}
            >
                <option value="1">1</option>
                <option value="2">2</option>
                <option value="3">3</option>
            </FormControl>
            <Button onclick={this.getSelectValue}>
                Get Select value
            </Button>
        </div>
    }
}

2 Comments

Would I be able to know why this answer was down voted initially? I'm really new to react, and I would like to know whether this is a proper implementation or not.
@NivedithaKarmegam same issue I've been having here at SO ever since I joined, people down-voting without giving an answer why is really a problem. Regarding your question whether it's a proper implementation, it depends, at the time of writing this answer works I'm not sure about the recent updates. So my personal philosophy is if it works and you don't need to bother updating your library and want to be productive then this approach is for you. Otherwise, react-bootstrap documentation is your best friend because even accepted answers here at SO gets stale as well.
0
  1. Event Handler should be as below:
const changeLanguage = (event: any)=> {
  console.log('Selected Index : ', event.target.selectedIndex);
}
  1. JSX should contain following:
<Form.Control as="select" onChange={(event)=>{changeLanguage(event)}}>                
  <option>English</option>
  <option>Marathi</option>
</Form.Control>

Note: This solution works with function components. For class components we need to change the syntax accordingly.

Comments

0

𝗘𝘀𝘁𝗮𝘀 𝘀𝗼𝗻 𝘁𝗿𝗲𝘀 𝗳𝗼𝗿𝗺𝗮𝘀 𝗱𝗲 𝗮𝗯𝘀𝘁𝗿𝗮𝗲𝗿 𝘃𝗮𝗹𝗼𝗿𝗲𝘀 𝗱𝗲 𝗶𝗻𝗽𝘂𝘁𝘀 𝗲𝗻 𝘂𝗻 𝗳𝗼𝗿𝗺𝘂𝗹𝗮𝗿𝗶𝗼 𝗱𝗲 𝗥𝗲𝗮𝗰𝘁 𝗕𝗼𝗼𝘁𝘀𝘁𝗿𝗮𝗽:

Teniendo en cuenta que en la actualidad existe uso obsoleto de getDOMNode() y uso obsoleto de findDOMNode()

import * as React from 'react'
import Form from 'react-bootstrap/Form'

𝟭. 𝗰𝗼𝗻𝘁𝗿𝗼𝗹𝗜𝗱 & 𝗴𝗲𝘁𝗘𝗹𝗲𝗺𝗲𝗻𝘁𝗕𝘆𝗜𝗱

const Componente1 = (props) => {
    let clave = document.getElementById('formSignupPassword').value
    console.log(clave)
    return (
        <>
            <Form>
                <Form.Group className="mb-2" controlId="formSignupPassword">
                    <Form.Label className="mb-0">Contraseña</Form.Label>
                    <Form.Control
                        type="password"
                        placeholder="Registre una clave"
                    />
                </Form.Group>
            </Form>
        </>
    )
}

𝟮. 𝗿𝗲𝗳 & 𝗥𝗲𝗮𝗰𝘁.𝗰𝗿𝗲𝗮𝘁𝗲𝗥𝗲𝗳

const Componente2 = (props) => {
    let passwordText = React.createRef()
    let clave = passwordText.current.value
    console.log(clave)
    return (
        <>
            <Form>
                <Form.Group className="mb-2" controlId="formSignupPassword">
                    <Form.Label className="mb-0">Contraseña</Form.Label>
                    <Form.Control
                        type="password"
                        placeholder="Registre una clave"
                        inputRef={passwordText}
                        // or Use
                        ref={passwordText}
                    />
                </Form.Group>
            </Form>
        </>
    )
}

𝟯. 𝗼𝗻𝗖𝗵𝗮𝗻𝗴𝗲={(𝗲) =>} & 𝗛𝗼𝗼𝗸𝘀 𝗥𝗲𝗮𝗰𝘁.𝘂𝘀𝗲𝗦𝘁𝗮𝘁𝗲

const Componente3 = (props) => {
    const [userEmail, setEmail] = React.useState(null)
    console.log(userEmail)
    return (
        <>
            <Form>
                <Form.Group className="mb-2" controlId="formSignupEmail">
                    <Form.Label className="mb-0">Email</Form.Label>
                    <Form.Control
                        type="email"
                        placeholder="Registre una cuenta de email valida"
                        onChange={(e) => setEmail(e.target.value)}
                    />
                </Form.Group>
            </Form>
        </>
    )
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.