Fix form reset for uncontrolled select elements (#11057)

* Set defaultSelected on option element from select's defaultValue

* Add form reset fixture for selects

* Pass explicit value for setDefaultSelected
This commit is contained in:
Brandon Dail
2017-10-10 08:54:59 -07:00
committed by Dan Abramov
parent b2101cb328
commit 5c6cb597f9
2 changed files with 68 additions and 6 deletions

View File

@@ -7,11 +7,23 @@ const ReactDOM = window.ReactDOM;
class SelectFixture extends React.Component {
state = {value: ''};
_nestedDOMNode = null;
_singleFormDOMNode = null;
_multipleFormDOMNode = null;
onChange = event => {
this.setState({value: event.target.value});
};
resetSingleOptionForm = event => {
event.preventDefault();
this._singleFormDOMNode.reset();
};
resetMultipleOptionForm = event => {
event.preventDefault();
this._multipleFormDOMNode.reset();
};
componentDidMount() {
this._renderNestedSelect();
}
@@ -100,6 +112,49 @@ class SelectFixture extends React.Component {
</select>
</div>
</TestCase>
<TestCase title="A single select being reset">
<TestCase.Steps>
<li>Open the select</li>
<li>Select "baz" or "foo"</li>
<li>Click the "Reset" button</li>
</TestCase.Steps>
<TestCase.ExpectedResult>
The select should be reset to the inital value, "bar"
</TestCase.ExpectedResult>
<div className="test-fixture">
<form ref={n => (this._singleFormDOMNode = n)}>
<select defaultValue="bar">
<option value="foo">foo</option>
<option value="bar">bar</option>
<option value="baz">baz</option>
</select>
<button onClick={this.resetSingleOptionForm}>Reset</button>
</form>
</div>
</TestCase>
<TestCase title="A multiple select being reset">
<TestCase.Steps>
<li>Select any combination of options</li>
<li>Click the "Reset" button</li>
</TestCase.Steps>
<TestCase.ExpectedResult>
The select should be reset to the initial values "foo" and "baz"
</TestCase.ExpectedResult>
<div className="test-fixture">
<form ref={n => (this._multipleFormDOMNode = n)}>
<select multiple defaultValue={['foo', 'baz']}>
<option value="foo">foo</option>
<option value="bar">bar</option>
<option value="baz">baz</option>
</select>
<button onClick={this.resetMultipleOptionForm}>Reset</button>
</form>
</div>
</TestCase>
</FixtureSet>
);
}

View File

@@ -76,6 +76,7 @@ function updateOptions(
node: HTMLSelectElement,
multiple: boolean,
propValue: any,
setDefaultSelected: boolean,
) {
type IndexableHTMLOptionsCollection = HTMLOptionsCollection & {
[key: number]: HTMLOptionElement,
@@ -94,6 +95,9 @@ function updateOptions(
if (options[i].selected !== selected) {
options[i].selected = selected;
}
if (selected && setDefaultSelected) {
options[i].defaultSelected = true;
}
}
} else {
// Do not set `select.value` as exact behavior isn't consistent across all
@@ -103,6 +107,9 @@ function updateOptions(
for (let i = 0; i < options.length; i++) {
if (options[i].value === selectedValue) {
options[i].selected = true;
if (setDefaultSelected) {
options[i].defaultSelected = true;
}
return;
}
if (defaultSelected === null && !options[i].disabled) {
@@ -173,9 +180,9 @@ var ReactDOMSelect = {
node.multiple = !!props.multiple;
var value = props.value;
if (value != null) {
updateOptions(node, !!props.multiple, value);
updateOptions(node, !!props.multiple, value, false);
} else if (props.defaultValue != null) {
updateOptions(node, !!props.multiple, props.defaultValue);
updateOptions(node, !!props.multiple, props.defaultValue, true);
}
},
@@ -190,14 +197,14 @@ var ReactDOMSelect = {
var value = props.value;
if (value != null) {
updateOptions(node, !!props.multiple, value);
updateOptions(node, !!props.multiple, value, false);
} else if (wasMultiple !== !!props.multiple) {
// For simplicity, reapply `defaultValue` if `multiple` is toggled.
if (props.defaultValue != null) {
updateOptions(node, !!props.multiple, props.defaultValue);
updateOptions(node, !!props.multiple, props.defaultValue, true);
} else {
// Revert the select back to its default unselected state.
updateOptions(node, !!props.multiple, props.multiple ? [] : '');
updateOptions(node, !!props.multiple, props.multiple ? [] : '', false);
}
}
},
@@ -207,7 +214,7 @@ var ReactDOMSelect = {
var value = props.value;
if (value != null) {
updateOptions(node, !!props.multiple, value);
updateOptions(node, !!props.multiple, value, false);
}
},
};