mirror of https://github.com/sveltejs/svelte
The client only handled `defaultValue` in the non-spread path, so
`<select {...props}>` compiled to `attribute_effect` and never reached
`set_default_select_value`. `set_attributes` can't apply it either,
since assigning the property does nothing on a select. It now marks the
default option from the same effect that handles `value`, after the
options exist.
Server-side the key was only read as `defaultvalue`. That is what the
compiler emits for an attribute written in the template, but a spread
passes keys through as the user wrote them, so `defaultValue` was
ignored and SSR disagreed with the client. Both spellings are accepted
now.
This is the case #18447 was filed for: `<select {...form.fields.x.as('select')}>`
in SvelteKit is always a spread.
pull/18591/head
parent
5cfa5495a0
commit
22c07e69bc
@ -0,0 +1,56 @@
|
||||
import { test } from '../../test';
|
||||
import { flushSync } from 'svelte';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
/**
|
||||
* @param {NodeListOf<any>} options
|
||||
* @param {any[]} selected
|
||||
*/
|
||||
function check_options(options, selected) {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
assert.equal(options[i].selected, selected[i], `option ${i}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLOptionElement} option
|
||||
*/
|
||||
function select_option(option) {
|
||||
option.selected = true;
|
||||
option.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
|
||||
const reset = /** @type {HTMLInputElement} */ (target.querySelector('input[type=reset]'));
|
||||
const [test1, test2] = target.querySelectorAll('select');
|
||||
const [test1_span] = target.querySelectorAll('span');
|
||||
|
||||
// a spread carrying defaultValue selects the matching option
|
||||
{
|
||||
const options = test1.querySelectorAll('option');
|
||||
check_options(options, [false, true, false]);
|
||||
assert.htmlEqual(test1_span.innerHTML, 'b');
|
||||
}
|
||||
|
||||
// value in the same spread still wins over defaultValue
|
||||
{
|
||||
const options = test2.querySelectorAll('option');
|
||||
check_options(options, [false, false, true]);
|
||||
}
|
||||
|
||||
// changing the selection and resetting goes back to defaultValue
|
||||
select_option(test1.querySelectorAll('option')[2]);
|
||||
select_option(test2.querySelectorAll('option')[0]);
|
||||
flushSync();
|
||||
|
||||
assert.htmlEqual(test1_span.innerHTML, 'c');
|
||||
|
||||
reset.click();
|
||||
await Promise.resolve();
|
||||
flushSync();
|
||||
|
||||
check_options(test1.querySelectorAll('option'), [false, true, false]);
|
||||
check_options(test2.querySelectorAll('option'), [false, true, false]);
|
||||
assert.htmlEqual(test1_span.innerHTML, 'b');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
let props1 = $state({ defaultValue: 'b' });
|
||||
let props2 = $state({ defaultValue: 'b', value: 'c' });
|
||||
|
||||
let selected = $state();
|
||||
</script>
|
||||
|
||||
<form>
|
||||
<!-- spread carrying defaultValue, no value -->
|
||||
<select {...props1} bind:value={selected}>
|
||||
<option value="a">A</option>
|
||||
<option value="b">B</option>
|
||||
<option value="c">C</option>
|
||||
</select>
|
||||
|
||||
<!-- spread carrying both, value wins -->
|
||||
<select {...props2}>
|
||||
<option value="a">A</option>
|
||||
<option value="b">B</option>
|
||||
<option value="c">C</option>
|
||||
</select>
|
||||
|
||||
<input type="reset" value="Reset" />
|
||||
</form>
|
||||
|
||||
<p><span class="test-1">{selected}</span></p>
|
||||
@ -0,0 +1,12 @@
|
||||
<select>
|
||||
<option value="a">A</option>
|
||||
<option selected="" value="b">B</option>
|
||||
</select>
|
||||
<select>
|
||||
<option value="a">A</option>
|
||||
<option selected="" value="b">B</option>
|
||||
</select>
|
||||
<select>
|
||||
<option selected="" value="a">A</option>
|
||||
<option value="b">B</option>
|
||||
</select>
|
||||
@ -0,0 +1,18 @@
|
||||
<script>
|
||||
const props = { defaultValue: 'b' };
|
||||
</script>
|
||||
|
||||
<select defaultValue="b">
|
||||
<option value="a">A</option>
|
||||
<option value="b">B</option>
|
||||
</select>
|
||||
|
||||
<select {...props}>
|
||||
<option value="a">A</option>
|
||||
<option value="b">B</option>
|
||||
</select>
|
||||
|
||||
<select defaultValue="b" value="a">
|
||||
<option value="a">A</option>
|
||||
<option value="b">B</option>
|
||||
</select>
|
||||
Loading…
Reference in new issue