Fix <input> with type date/time/etc. issue on mobile browsers (#7397)
Fix <input> with type date/time/etc. issue on mobile browsers
Keyan Zhang committed
Aug 2, 2016 at 12:56 UTC
8af6f9e5a2f74256b6dc955bbc8be3d90435151e
2 files changed
+73
-2
src/renderers/dom/client/wrappers/ReactDOMInput.js
+20
-2
@@ -230,8 +230,26 @@ var ReactDOMInput = {
230
// are not resetable nodes so this operation doesn't matter and actually
231
// removes browser-default values (eg "Submit Query") when no value is
232
// provided.
233
- if (props.type !== 'submit' && props.type !== 'reset') {
234
- node.value = node.value;
233
+
234
+ switch (props.type) {
235
+ case 'submit':
236
+ case 'reset':
237
+ break;
238
+ case 'color':
239
+ case 'date':
240
+ case 'datetime':
241
+ case 'datetime-local':
242
+ case 'month':
243
+ case 'time':
244
+ case 'week':
245
+ // This fixes the no-show issue on iOS Safari and Android Chrome:
246
+ // https://github.com/facebook/react/issues/7233
247
+ node.value = '';
248
+ node.value = node.defaultValue;
249
+ break;
250
+ default:
251
+ node.value = node.value;
252
+ break;
253
}
254
255
// Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug
src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js
+53
@@ -82,6 +82,21 @@ describe('ReactDOMInput', function() {
82
expect(node.defaultValue).toBe('1');
83
});
84
85
+ it('should update `defaultValue` for uncontrolled date/time input', function() {
86
+ var container = document.createElement('div');
87
+
88
+ var node = ReactDOM.render(<input type="date" defaultValue="1980-01-01" />, container);
89
+
90
+ expect(node.value).toBe('1980-01-01');
91
+
92
+ ReactDOM.render(<input type="date" defaultValue="2000-01-01" />, container);
93
+
94
+ expect(node.value).toBe('1980-01-01');
95
+ expect(node.defaultValue).toBe('2000-01-01');
96
+
97
+ ReactDOM.render(<input type="date" />, container);
98
+ });
99
+
100
it('should take `defaultValue` when changing to uncontrolled input', function() {
101
var container = document.createElement('div');
102
@@ -790,4 +805,42 @@ describe('ReactDOMInput', function() {
805
expect(node.value).toEqual('Test');
806
});
807
808
+ it('resets value of date/time input to fix bugs in iOS Safari', function() {
809
+ // https://github.com/facebook/react/issues/7233
810
+ if (!ReactDOMFeatureFlags.useCreateElement) {
811
+ return;
812
+ }
813
+
814
+ function strify(x) {
815
+ return JSON.stringify(x, null, 2);
816
+ }
817
+
818
+ var log = [];
819
+ var originalCreateElement = document.createElement;
820
+ spyOn(document, 'createElement').and.callFake(function(type) {
821
+ var el = originalCreateElement.apply(this, arguments);
822
+ if (type === 'input') {
823
+ Object.defineProperty(el, 'value', {
824
+ set: function(val) {
825
+ log.push(`node.value = ${strify(val)}`);
826
+ },
827
+ });
828
+ spyOn(el, 'setAttribute').and.callFake(function(name, val) {
829
+ log.push(`node.setAttribute(${strify(name)}, ${strify(val)})`);
830
+ });
831
+ }
832
+ return el;
833
+ });
834
+
835
+ ReactTestUtils.renderIntoDocument(<input type="date" defaultValue="1980-01-01" />);
836
+ expect(log).toEqual([
837
+ 'node.setAttribute("data-reactroot", "")',
838
+ 'node.setAttribute("type", "date")',
839
+ 'node.setAttribute("value", "1980-01-01")',
840
+ 'node.value = ""',
841
+ 'node.value = ""',
842
+ 'node.setAttribute("checked", "")',
843
+ 'node.setAttribute("checked", "")',
844
+ ]);
845
+ });
846
});