diff --git a/src/browser/ui/dom/components/ReactDOMInput.js b/src/browser/ui/dom/components/ReactDOMInput.js
index 49f783c1e12..799f368e975 100644
--- a/src/browser/ui/dom/components/ReactDOMInput.js
+++ b/src/browser/ui/dom/components/ReactDOMInput.js
@@ -51,6 +51,22 @@ function forceUpdateIfMounted() {
*
* @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
*/
+
+function getKeyForType(props) {
+ // Returning `'text'` makes sense but will throw in IE8 when mutated as an
+ // attribute and would cause a toggling attribute in other browsers.
+ // Ultimately very much an edge case, but `''` seems overall preferable.
+ return props.type != null ? props.type : '';
+}
+
+function getInitialState(props) {
+ var defaultValue = props.defaultValue;
+ return {
+ initialChecked: props.defaultChecked || false,
+ initialValue: defaultValue != null ? defaultValue : null
+ };
+}
+
var ReactDOMInput = ReactClass.createClass({
displayName: 'ReactDOMInput',
tagName: 'INPUT',
@@ -58,17 +74,18 @@ var ReactDOMInput = ReactClass.createClass({
mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
getInitialState: function() {
- var defaultValue = this.props.defaultValue;
- return {
- initialChecked: this.props.defaultChecked || false,
- initialValue: defaultValue != null ? defaultValue : null
- };
+ return getInitialState(this.props);
},
render: function() {
// Clone `this.props` so we don't mutate the input.
var props = assign({}, this.props);
+ // IE8 does not support changing input `type`. IE does not remember
+ // `checked` if `type` isn't `checkbox` or `radio`. It's also really weird
+ // to reconcile inputs with different `type` as if they were the same.
+ props.key = getKeyForType(props);
+
props.defaultChecked = null;
props.defaultValue = null;
@@ -83,6 +100,12 @@ var ReactDOMInput = ReactClass.createClass({
return input(props, this.props.children);
},
+ componentWillReceiveProps: function(nextProps) {
+ if (getKeyForType(this.props) !== getKeyForType(nextProps)) {
+ this.replaceState(getInitialState(nextProps));
+ }
+ },
+
componentDidMount: function() {
var id = ReactMount.getID(findDOMNode(this));
instancesByReactID[id] = this;
diff --git a/src/browser/ui/dom/components/__tests__/ReactDOMInput-test.js b/src/browser/ui/dom/components/__tests__/ReactDOMInput-test.js
index f67d43d1b8e..0c19e13f25a 100644
--- a/src/browser/ui/dom/components/__tests__/ReactDOMInput-test.js
+++ b/src/browser/ui/dom/components/__tests__/ReactDOMInput-test.js
@@ -82,7 +82,7 @@ describe('ReactDOMInput', function() {
expect(node.value).toBe('yolo');
- stub.replaceProps({value: true, onChange: emptyFunction});
+ stub.replaceProps({value: true, type: 'text', onChange: emptyFunction});
expect(node.value).toEqual('true');
});
@@ -93,7 +93,7 @@ describe('ReactDOMInput', function() {
expect(node.value).toBe('yolo');
- stub.replaceProps({value: false});
+ stub.replaceProps({value: false, type: 'text'});
expect(node.value).toEqual('false');
});
@@ -110,7 +110,11 @@ describe('ReactDOMInput', function() {
}
};
- stub.replaceProps({value: objToString, onChange: emptyFunction});
+ stub.replaceProps({
+ value: objToString,
+ type: 'text',
+ onChange: emptyFunction
+ });
expect(node.value).toEqual('foobar');
});
@@ -196,6 +200,40 @@ describe('ReactDOMInput', function() {
expect(cNode.checked).toBe(true);
});
+ it('should not remount when adding type text', function() {
+ var node = document.createElement('div');
+
+ React.render(
+ ,
+ node
+ );
+
+
+ });
+
+ it('should remount when changing type', function() {
+ var node = document.createElement('div');
+
+ React.render(
+ ,
+ node
+ );
+
+ var stub = React.render(
+ ,
+ node
+ );
+
+ expect(stub.getDOMNode().value).toBe('foo');
+
+ stub = React.render(
+ ,
+ node
+ );
+
+ expect(stub.getDOMNode().value).toBe('bar');
+ });
+
it('should support ReactLink', function() {
var link = new ReactLink('yolo', mocks.getMockFunction());
var instance = ;