From 31794f5f9f03d228d4f0597c539da75a6df1fec9 Mon Sep 17 00:00:00 2001 From: jquense Date: Wed, 6 May 2015 12:55:26 -0400 Subject: [PATCH 1/3] Normalize onChange behavior in IE for placeholders Checks for actual changes to the value, eliminating the case where empty --- .../ui/dom/components/ReactDOMInput.js | 34 +++++++++++++++++++ .../ui/dom/components/ReactDOMTextarea.js | 30 ++++++++++++++++ .../__tests__/ReactDOMInput-test.js | 16 +++++++++ .../__tests__/ReactDOMTextarea-test.js | 16 +++++++++ 4 files changed, 96 insertions(+) diff --git a/src/browser/ui/dom/components/ReactDOMInput.js b/src/browser/ui/dom/components/ReactDOMInput.js index 49f783c1e1264..163193a559b7a 100644 --- a/src/browser/ui/dom/components/ReactDOMInput.js +++ b/src/browser/ui/dom/components/ReactDOMInput.js @@ -19,6 +19,7 @@ var ReactClass = require('ReactClass'); var ReactElement = require('ReactElement'); var ReactMount = require('ReactMount'); var ReactUpdates = require('ReactUpdates'); +var isTextInputElement = require('isTextInputElement'); var assign = require('Object.assign'); var findDOMNode = require('findDOMNode'); @@ -28,6 +29,7 @@ var input = ReactElement.createFactory('input'); var instancesByReactID = {}; + function forceUpdateIfMounted() { /*jshint validthis:true */ if (this.isMounted()) { @@ -35,6 +37,13 @@ function forceUpdateIfMounted() { } } +function isIeInputEvent(event) { + return ('documentMode' in document) + && document.documentMode > 9 + && event.nativeEvent.type === 'input' + && isTextInputElement(event.target); +} + /** * Implements an native component that allows setting these optional * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. @@ -57,8 +66,15 @@ var ReactDOMInput = ReactClass.createClass({ mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin], + componentWillMount: function() { + var defaultValue = this.props.defaultValue; + + this._uncontrolledValue = defaultValue != null ? '' + defaultValue : ''; + }, + getInitialState: function() { var defaultValue = this.props.defaultValue; + return { initialChecked: this.props.defaultChecked || false, initialValue: defaultValue != null ? defaultValue : null @@ -115,6 +131,24 @@ var ReactDOMInput = ReactClass.createClass({ _handleChange: function(event) { var returnValue; var onChange = LinkedValueUtils.getOnChange(this.props); + + // IE 10+ fire input events when setting/unsetting a placeholder + // we guard against it by checking if the next and + // last values are both empty and bailing out of the change + // https://github.com/facebook/react/issues/3484 + if ( isIeInputEvent(event) ) { + var controlledValue = LinkedValueUtils.getValue(this.props); + var lastValue = controlledValue != null ? + '' + controlledValue : + this._uncontrolledValue; + + this._uncontrolledValue = event.target.value; + + if ( event.target.value === '' && lastValue === '') { + return returnValue; + } + } + if (onChange) { returnValue = onChange.call(this, event); } diff --git a/src/browser/ui/dom/components/ReactDOMTextarea.js b/src/browser/ui/dom/components/ReactDOMTextarea.js index 0261005c40ca4..0db22c5c7f3ca 100644 --- a/src/browser/ui/dom/components/ReactDOMTextarea.js +++ b/src/browser/ui/dom/components/ReactDOMTextarea.js @@ -34,6 +34,12 @@ function forceUpdateIfMounted() { } } +function isIeInputEvent(event) { + return ('documentMode' in document) + && document.documentMode > 9 + && event.nativeEvent.type === 'input'; +} + /** * Implements a