diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index 775a36fc56..ec439c34de 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -137,9 +137,6 @@ export default class AttributeWrapper extends BaseAttributeWrapper { ); updater = b`${method}(${element.var}, "${name}", ${should_cache ? this.last : value});`; } else if (property_name) { - block.chunks.hydrate.push( - b`${element.var}.${property_name} = ${init};` - ); const is_selected = property_name === 'selected'; const is_boolean = typeof init.value === 'boolean'; const attr_val = is_boolean ? x`""` : init; @@ -147,6 +144,10 @@ export default class AttributeWrapper extends BaseAttributeWrapper { block.chunks.hydrate.push( b`${method}(${element.var}, "${name}", ${attr_val});` ); + } else { + block.chunks.hydrate.push( + b`${element.var}.${property_name} = ${init};` + ); } updater = block.renderer.options.dev ? b`@prop_dev(${element.var}, "${property_name}", ${should_cache ? this.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 9ec36b12d7..2b4db9c064 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -669,9 +669,10 @@ export default class ElementWrapper extends Wrapper { dependencies.add(dep); } } - + block.chunks.mount.push(b` - (${data}.multiple ? @select_options : @select_option)(${this.var}, ${data}.value); + ('value' in ${data} && !${data}.multiple && @select_option(${this.var}, ${data}.value)); + (${data}.multiple && @select_options(${this.var}, ${data}.value)); `); block.chunks.update.push(b` if (${block.renderer.dirty(Array.from(dependencies))} && 'value' in ${data}) (${data}.multiple ? @select_options : @select_option)(${this.var}, ${data}.value);; diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 4e88882ac2..61d4a300f8 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -534,17 +534,15 @@ export function set_style(node, key, value, important) { } export function select_option(select, value) { - let count_selected_attr = 0; for (let i = 0; i < select.options.length; i += 1) { const option = select.options[i]; - if (option.hasAttribute('selected')) count_selected_attr++; if (option.__value === value) { option.selected = true; return; } } - if (count_selected_attr === 0) select.selectedIndex = -1; // no option should be selected + select.selectedIndex = -1; // no option should be selected } export function select_options(select, value) { @@ -556,6 +554,14 @@ export function select_options(select, value) { export function select_value(select) { const selected_option = select.querySelector(':checked') || select.options[0]; + if (select.selectedIndex === -1) { + for (let i = 0; i < select.options.length; i += 1) { + const option = select.options[i]; + if (option.hasAttribute('selected')) { + return option.__value; + } + } + } return selected_option && selected_option.__value; } @@ -728,4 +734,4 @@ export function get_custom_elements_slots(element: HTMLElement) { result[node.slot || 'default'] = true; }); return result; -} +} \ No newline at end of file diff --git a/test/runtime/samples/binding-select-unmatched-with-void/_config.js b/test/runtime/samples/binding-select-unmatched-with-void/_config.js new file mode 100644 index 0000000000..5e0137a336 --- /dev/null +++ b/test/runtime/samples/binding-select-unmatched-with-void/_config.js @@ -0,0 +1,17 @@ +// This test make sure if value is bind value is (void 0) then +// it should set to same as the selected option value +export default { + async test({ assert, target }) { + assert.htmlEqual(target.innerHTML, ` +

selected: c

+ + + +

selected: c

+ `); + } +}; diff --git a/test/runtime/samples/binding-select-unmatched-with-void/main.svelte b/test/runtime/samples/binding-select-unmatched-with-void/main.svelte new file mode 100644 index 0000000000..d5d50d5895 --- /dev/null +++ b/test/runtime/samples/binding-select-unmatched-with-void/main.svelte @@ -0,0 +1,14 @@ + + +

selected: {selected}

+ + + +

selected: {selected}

\ No newline at end of file diff --git a/test/runtime/samples/binding-select-unmatched/_config.js b/test/runtime/samples/binding-select-unmatched/_config.js index 99e7d23927..e40a330764 100644 --- a/test/runtime/samples/binding-select-unmatched/_config.js +++ b/test/runtime/samples/binding-select-unmatched/_config.js @@ -9,6 +9,8 @@ export default {

selected: null

+ + `, async test({ assert, component, target }) { @@ -22,6 +24,30 @@ export default { assert.equal(select.selectedIndex, -1); assert.ok(!options[0].selected); + const addAttrButton = target.querySelector('#add-attr'); + addAttrButton.click(); + assert.equal(select.value, 'c'); + // since svelte don't listen the change, the binded value + // will be null even though there selectedIndex !== -1 + assert.htmlEqual(target.innerHTML, ` +

selected: null

+ + + +

selected: null

+ + + `); + assert.equal(select.selectedIndex, 2); + assert.ok(options[2].selected); + + const removeAttrButton = target.querySelector('#remove-attr'); + removeAttrButton.click(); + component.selected = 'a'; // first option should now be selected assert.equal(select.value, 'a'); assert.ok(options[0].selected); @@ -36,6 +62,8 @@ export default {

selected: a

+ + `); component.selected = 'd'; // doesn't match an option @@ -55,6 +83,8 @@ export default {

selected: d

+ + `); } }; diff --git a/test/runtime/samples/binding-select-unmatched/main.svelte b/test/runtime/samples/binding-select-unmatched/main.svelte index 20e13f4765..a6e88731c5 100644 --- a/test/runtime/samples/binding-select-unmatched/main.svelte +++ b/test/runtime/samples/binding-select-unmatched/main.svelte @@ -1,6 +1,7 @@

selected: {selected}

@@ -8,7 +9,9 @@ -

selected: {selected}

\ No newline at end of file +

selected: {selected}

+ + \ No newline at end of file diff --git a/test/runtime/samples/select-unmatched-with-spread/_config.js b/test/runtime/samples/select-unmatched-with-spread/_config.js new file mode 100644 index 0000000000..a672f152c9 --- /dev/null +++ b/test/runtime/samples/select-unmatched-with-spread/_config.js @@ -0,0 +1,18 @@ +export default { + html: ` +

selected: undefined

+ + + +

selected: undefined

+ `, + + async test({ assert, target }) { + const select = target.querySelector('select'); + assert.equal(select.value, 'c'); + } +}; diff --git a/test/runtime/samples/select-unmatched-with-spread/main.svelte b/test/runtime/samples/select-unmatched-with-spread/main.svelte new file mode 100644 index 0000000000..eeb89324d4 --- /dev/null +++ b/test/runtime/samples/select-unmatched-with-spread/main.svelte @@ -0,0 +1,14 @@ + + +

selected: {selected}

+ + + +

selected: {selected}

\ No newline at end of file