Repository: sveltejs/svelte (JavaScript)
Date: 2017-04-12 23:59:38+00:00
Task type: Bug Fix

Issue:
Select menu bind:value does not work to dynamically set options/values
I could have sworn this worked at some point, but I went back through different svelte versions and it seems to have always been an issue:

https://svelte.technology/repl?version=1.14.1&gist=155b2b84c2c9084986fd169a50c2b3dc

Changing the `bind:value="something"`  to `value="{{ something }}"` does seem to work:

https://svelte.technology/repl?version=1.14.1&gist=a82840366f505969aa34964c6a87b7b1
Select menu bind:value does not work to dynamically set options/values
I could have sworn this worked at some point, but I went back through different svelte versions and it seems to have always been an issue:

https://svelte.technology/repl?version=1.14.1&gist=155b2b84c2c9084986fd169a50c2b3dc

Changing the `bind:value="something"`  to `value="{{ something }}"` does seem to work:

https://svelte.technology/repl?version=1.14.1&gist=a82840366f505969aa34964c6a87b7b1


Issue discussion:

Solution patch:
diff --git a/src/generators/dom/visitors/Element/Element.js b/src/generators/dom/visitors/Element/Element.js
--- a/src/generators/dom/visitors/Element/Element.js
+++ b/src/generators/dom/visitors/Element/Element.js
@@ -63,7 +63,7 @@ export default function visitElement ( generator, block, state, node ) {
 		.forEach( attribute => {
 			// <select> value attributes are an annoying special case — it must be handled
 			// *after* its children have been updated
-			if ( attribute.type === 'Attribute' && attribute.name === 'value' && node.name === 'select' ) {
+			if ( ( attribute.type === 'Attribute' || attribute.type === 'Binding' ) && attribute.name === 'value' && node.name === 'select' ) {
 				selectValueAttribute = attribute;
 				return;
 			}
@@ -74,12 +74,7 @@ export default function visitElement ( generator, block, state, node ) {
 	// special case – bound <option> without a value attribute
 	if ( node.name === 'option' && !node.attributes.find( attribute => attribute.type === 'Attribute' && attribute.name === 'value' ) ) { 	// TODO check it's bound
 		const statement = `${name}.__value = ${name}.textContent;`;
-		block.builders.update.addLine( statement );
-		node.initialUpdate = statement;
-	}
-
-	if ( node.initialUpdate ) {
-		block.builders.create.addBlock( node.initialUpdate );
+		node.initialUpdate = node.lateUpdate = statement;
 	}
 
 	if ( childState.allUsedContexts.length || childState.usesComponent ) {
@@ -117,8 +112,17 @@ export default function visitElement ( generator, block, state, node ) {
 		visit( generator, block, childState, child );
 	});
 
+	if ( node.initialUpdate ) {
+		block.builders.create.addBlock( node.initialUpdate );
+	}
+
+	if ( node.lateUpdate ) {
+		block.builders.update.addLine( node.lateUpdate );
+	}
+
 	if ( selectValueAttribute ) {
-		visitAttribute( generator, block, childState, node, selectValueAttribute );
+		const visitor = selectValueAttribute.type === 'Attribute' ? visitAttribute : visitBinding;
+		visitor( generator, block, childState, node, selectValueAttribute );
 	}
 }
 


Test patch:
diff --git a/test/runtime/samples/binding-select-late/_config.js b/test/runtime/samples/binding-select-late/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/binding-select-late/_config.js
@@ -0,0 +1,34 @@
+export default {
+	data: {
+		items: [],
+		selected: null
+	},
+
+	html: `
+		<select></select>
+		<p>selected: nothing</p>
+	`,
+
+	test ( assert, component, target ) {
+		component.set({
+			items: [ 'one', 'two', 'three' ],
+			selected: 'two'
+		});
+
+		const options = target.querySelectorAll( 'option' );
+		assert.ok( !options[0].selected );
+		assert.ok( options[1].selected );
+		assert.ok( !options[2].selected );
+
+		assert.htmlEqual( target.innerHTML, `
+			<select>
+				<option>one</option>
+				<option>two</option>
+				<option>three</option>
+			</select>
+			<p>selected: two</p>
+		` );
+
+		component.destroy();
+	}
+};
diff --git a/test/runtime/samples/binding-select-late/main.html b/test/runtime/samples/binding-select-late/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/binding-select-late/main.html
@@ -0,0 +1,7 @@
+<select bind:value='selected'>
+	{{#each items as item}}
+		<option>{{item}}</option>
+	{{/each}}
+</select>
+
+<p>selected: {{selected || 'nothing'}}</p>