Question

I have a Form component that I am building in React and this form has some Field components as children. I am using these components to build a log in form that has an email address and password. My form has an onSubmit handler that serializes its children (Fields) and sends off an AJAX request.

Everything is working well in the normal case. But, when browsers like Chrome Autofill the form with my email address and password, the serialization doesn't pick up the values of the inputs.

Field currently looks something like this:

/** @jsx React.DOM */

var Field = React.createClass({
  serialize: function() {
    return { name: this.props.name, value: this.refs.field.state.value };
  },

  render: function() {
    return (
      <div>
        <label>
          {this.props.label}
          <input type={this.props.type} ref="field"
            name={this.props.name}
            defaultValue={this.props.value} />
        </label>
      </div>
    )
  }
});

How do I get the browser Autofill value to show up in my serialized Field data?

Was it helpful?

Solution

State should flow in one direction, from the top layer down to the bottom. So reaching into a child element to get its state is a bad idea. To accomplish the serialization with this structure, you simply need to reach into the DOM to get the value of the input. In the code example above, the serialize method should be:

serialize: function() {
  return { name: this.props.name, value: this.refs.field.getDOMNode().value };
},

OTHER TIPS

Using onChange event is the most common scenario to update whatever model property bound to a component, but you can also use onBlur to catch the values when the form is "auto-filled" by the browser.

var Input = React.createClass({
  getInitialState: function() {
    return {typed: ''};
  },
  onBlur: function(event) {
    this.setState({typed: event.target.value});
  },
  render: function() {
    return <div>
        <input type="text" onBlur={this.onBlur.bind(this)}/>
        You typed: <code>{this.state.typed}</code>
      </div>
  }
});

This is my solution using refs :) ..basically I trigger the change events manually for the first second..the reason behind is that every browser is handling autofill in a different way and this changes based on browser version..there is no way to cover this properly as of now

  componentDidMount () {
    let tries = 4;
    this.int  = setInterval(() => {
      tries--;
      if (tries === 0) {
        this._createChangeEvent();
        clearInterval(this.int);
      }
    }, 300);
  }

  _createChangeEvent = () => {
    if ("createEvent" in document) {
      const evt = document.createEvent("HTMLEvents");
      evt.initEvent("change", false, true);
      this.input.dispatchEvent(evt);
    } else {
      this.input.fireEvent("onchange");
    }
  };
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top