kg.
kg.

Reputation: 561

ReactJS: How to access an array of form input children?

I have the following form which I would like to have a dynamic number of player name input fields, passed to PlayerSelect as props.numPlayers, and would like it to read the user input from each of those fields and pass the names as an array to this.props.setPlayers, which is a callback passed from the parent component.

I am trying to find the right way to access the PlayerNameInput components from the parent, as following doesn't seem to be working:

var PlayerSelect = React.createClass({
  getPlayers: function() {
    var playerNames = []
    for (var i = 0; i < this.players.length; i++) {
      var playerName = this.players[i].getDOMNode().value.trim();
      playerNames.push(playerName);
    }
    this.props.setPlayers(playerNames);
  },
  render: function() {
    this.players = []
    for (var i = 0; i < this.props.numPlayers; i++) {
      this.players.push(<PlayerNameInput />);
    }
    return (
      <div className="page">
        <form className="player-select">
          <ol className="players">
            {this.players}
          </ol>
          <button onClick={this.getPlayers}>Done</button>
        </form>
      </div>
    );
  }
});

var PlayerNameInput = React.createClass({
  render: function() {
    return (
      <li><input type="text"/></li>
    );
  }
});

Upvotes: 2

Views: 4022

Answers (1)

daniula
daniula

Reputation: 7028

You can use ref to access DOM node:

var PlayerSelect = React.createClass({
  getInitialState: function() { return { names: [] } },
  getPlayers: function(event) {
    event.preventDefault();
    var playerNames = []
    for (var i = 0; i < this.props.numPlayers; i++) {
      var playerName = this.refs['player-' + i].getDOMNode().value.trim();
      playerNames.push(playerName);
    }
    this.setState({ names: playerNames });
  },
  render: function() {
    var players = []
    for (var i = 0; i < this.props.numPlayers; i++) {
      players.push(
          <li key={'player-' + i}>
              <input ref={ 'player-' + i } type="text"/>
          </li>
      );
    }
    return (
      <div className="page">
        <form className="player-select">
          <ol className="players">
            {players}
          </ol>
          <button onClick={this.getPlayers}>Done</button>
        </form>
        <div>{ this.state.names.join(', ') }</div>
      </div>
    );
  }
});

JSFiddle

Also remember:

  • when you create array of elements every single one has to have unique key
  • don't modify props of your component to communicate with outside modules. Use some other library which provides models to communicate between components, for example Backbone or Flux ( in my example for simplicity I just saved collected player names to components state ).

Upvotes: 4

Related Questions