diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts
index 85f252f57e..ca941b7be9 100644
--- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts
+++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts
@@ -102,25 +102,12 @@ export default class AttributeWrapper {
} else if (is_select_value_attribute) {
// annoying special case
const is_multiple_select = element.node.get_static_attribute_value('multiple');
- const i = block.get_unique_name('i');
- const option = block.get_unique_name('option');
-
- const if_statement = is_multiple_select
- ? b`
- ${option}.selected = ~${last}.indexOf(${option}.__value);`
- : b`
- if (${option}.__value === ${last}) {
- ${option}.selected = true;
- ${{ type: 'BreakStatement' }};
- }`; // TODO the BreakStatement is gross, but it's unsyntactic otherwise...
-
- updater = b`
- for (var ${i} = 0; ${i} < ${element.var}.options.length; ${i} += 1) {
- var ${option} = ${element.var}.options[${i}];
-
- ${if_statement}
- }
- `;
+
+ if (is_multiple_select) {
+ updater = b`@select_options(${element.var}, ${last});`;
+ } else {
+ updater = b`@select_option(${element.var}, ${last});`;
+ }
block.chunks.mount.push(b`
${last} = ${value};
diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts
index a50e02e76a..83bc8be94e 100644
--- a/src/compiler/compile/render_dom/wrappers/Element/index.ts
+++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts
@@ -705,10 +705,27 @@ export default class ElementWrapper extends Wrapper {
);
block.chunks.update.push(b`
- ${fn}(${this.var}, @get_spread_update(${levels}, [
+ ${fn}(${this.var}, ${data} = @get_spread_update(${levels}, [
${updates}
]));
`);
+
+ // handle edge cases for elements
+ if (this.node.name === 'select') {
+ const dependencies = new Set();
+ for (const attr of this.attributes) {
+ for (const dep of attr.node.dependencies) {
+ dependencies.add(dep);
+ }
+ }
+
+ block.chunks.mount.push(b`
+ if (${data}.multiple) @select_options(${this.var}, ${data}.value);
+ `);
+ block.chunks.update.push(b`
+ if (${block.renderer.dirty(Array.from(dependencies))} && ${data}.multiple) @select_options(${this.var}, ${data}.value);
+ `);
+ }
}
add_transitions(
diff --git a/test/js/samples/select-dynamic-value/expected.js b/test/js/samples/select-dynamic-value/expected.js
index a93a47bd3a..f1a913c65f 100644
--- a/test/js/samples/select-dynamic-value/expected.js
+++ b/test/js/samples/select-dynamic-value/expected.js
@@ -7,7 +7,8 @@ import {
init,
insert,
noop,
- safe_not_equal
+ safe_not_equal,
+ select_option
} from "svelte/internal";
function create_fragment(ctx) {
@@ -33,26 +34,11 @@ function create_fragment(ctx) {
append(select, option0);
append(select, option1);
select_value_value = /*current*/ ctx[0];
-
- for (var i = 0; i < select.options.length; i += 1) {
- var option = select.options[i];
-
- if (option.__value === select_value_value) {
- option.selected = true;
- break;
- }
- }
+ select_option(select, select_value_value);
},
p(ctx, [dirty]) {
if (dirty & /*current*/ 1 && select_value_value !== (select_value_value = /*current*/ ctx[0])) {
- for (var i = 0; i < select.options.length; i += 1) {
- var option = select.options[i];
-
- if (option.__value === select_value_value) {
- option.selected = true;
- break;
- }
- }
+ select_option(select, select_value_value);
}
},
i: noop,
diff --git a/test/runtime/samples/spread-element-input-seelct-multiple/_config.js b/test/runtime/samples/spread-element-input-seelct-multiple/_config.js
new file mode 100644
index 0000000000..1ddcd9eb6d
--- /dev/null
+++ b/test/runtime/samples/spread-element-input-seelct-multiple/_config.js
@@ -0,0 +1,39 @@
+export default {
+ async test({ assert, component, target, window }) {
+ const [input1, input2] = target.querySelectorAll('input');
+ const select = target.querySelector('select');
+ const [option1, option2] = select.childNodes;
+
+ let selections = Array.from(select.selectedOptions);
+ assert.equal(selections.length, 2);
+ assert.ok(selections.includes(option1));
+ assert.ok(selections.includes(option2));
+
+ const event = new window.Event('change');
+
+ input1.checked = false;
+ await input1.dispatchEvent(event);
+
+ selections = Array.from(select.selectedOptions);
+ assert.equal(selections.length, 1);
+ assert.ok(!selections.includes(option1));
+ assert.ok(selections.includes(option2));
+
+ input2.checked = false;
+ await input2.dispatchEvent(event);
+ input1.checked = true;
+ await input1.dispatchEvent(event);
+
+ selections = Array.from(select.selectedOptions);
+ assert.equal(selections.length, 1);
+ assert.ok(selections.includes(option1));
+ assert.ok(!selections.includes(option2));
+
+ component.spread = { value: ['Hello', 'World'] };
+
+ selections = Array.from(select.selectedOptions);
+ assert.equal(selections.length, 2);
+ assert.ok(selections.includes(option1));
+ assert.ok(selections.includes(option2));
+ }
+};
diff --git a/test/runtime/samples/spread-element-input-seelct-multiple/main.svelte b/test/runtime/samples/spread-element-input-seelct-multiple/main.svelte
new file mode 100644
index 0000000000..d2fb12dd20
--- /dev/null
+++ b/test/runtime/samples/spread-element-input-seelct-multiple/main.svelte
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file