Repository: sveltejs/svelte (JavaScript)
Date: 2017-08-13 18:18:50+00:00
Task type: Bug Fix

Issue:
input[type=range] + bind + ie11
It appears that bind applied to range inputs does not work on ie11.

`on:change` does work though.

https://svelte.technology/repl?version=1.27.0&gist=6f651445c5cb4c374b986be8cf5dcc29


Issue discussion:
Dammit IE! Since I can't easily test it, does the `change` event fire while you're still dragging in IE, or only after you've finished?
On IE11, the `change` event fires throughout the drag.

BTW, I did my testing on Browserstack.

To fix, I used both `on:change` & `bind`.
Hmm, to test the link above on IE11, it looks like you need to have a Promise polyfill.

I've been using `core-js/shim` from https://cdnjs.com/libraries/core-js.

Solution patch:
diff --git a/src/generators/dom/visitors/Element/Binding.ts b/src/generators/dom/visitors/Element/Binding.ts
--- a/src/generators/dom/visitors/Element/Binding.ts
+++ b/src/generators/dom/visitors/Element/Binding.ts
@@ -156,9 +156,26 @@ export default function visitBinding(
 		}
 	`);
 
-	block.builders.hydrate.addBlock(
-		`@addListener( ${state.parentNode}, '${eventName}', ${handler} );`
-	);
+	if (node.name === 'input' && type === 'range') {
+		// need to bind to `input` and `change`, for the benefit of IE
+		block.builders.hydrate.addBlock(deindent`
+			@addListener( ${state.parentNode}, 'input', ${handler} );
+			@addListener( ${state.parentNode}, 'change', ${handler} );
+		`);
+
+		block.builders.destroy.addBlock(deindent`
+			@removeListener( ${state.parentNode}, 'input', ${handler} );
+			@removeListener( ${state.parentNode}, 'change', ${handler} );
+		`);
+	} else {
+		block.builders.hydrate.addLine(
+			`@addListener( ${state.parentNode}, '${eventName}', ${handler} );`
+		);
+
+		block.builders.destroy.addLine(
+			`@removeListener( ${state.parentNode}, '${eventName}', ${handler} );`
+		);
+	}
 
 	if (node.name !== 'audio' && node.name !== 'video') {
 		node.initialUpdate = updateElement;
@@ -174,10 +191,6 @@ export default function visitBinding(
 		`);
 	}
 
-	block.builders.destroy.addLine(
-		`@removeListener( ${state.parentNode}, '${eventName}', ${handler} );`
-	);
-
 	if (attribute.name === 'paused') {
 		block.builders.create.addLine(
 			`@addListener( ${state.parentNode}, 'play', ${handler} );`


Test patch:
diff --git a/test/runtime/samples/binding-input-range-change/_config.js b/test/runtime/samples/binding-input-range-change/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/binding-input-range-change/_config.js
@@ -0,0 +1,33 @@
+export default {
+	data: {
+		count: 42
+	},
+
+	html: `
+		<input type='range'>
+		<p>number 42</p>
+	`,
+
+	test ( assert, component, target, window ) {
+		const input = target.querySelector( 'input' );
+		assert.equal( input.value, '42' );
+
+		const event = new window.Event( 'change' );
+
+		input.value = '43';
+		input.dispatchEvent( event );
+
+		assert.equal( component.get( 'count' ), 43 );
+		assert.htmlEqual( target.innerHTML, `
+			<input type='range'>
+			<p>number 43</p>
+		` );
+
+		component.set({ count: 44 });
+		assert.equal( input.value, '44' );
+		assert.htmlEqual( target.innerHTML, `
+			<input type='range'>
+			<p>number 44</p>
+		` );
+	}
+};
diff --git a/test/runtime/samples/binding-input-range-change/main.html b/test/runtime/samples/binding-input-range-change/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/binding-input-range-change/main.html
@@ -0,0 +1,2 @@
+<input type='range' bind:value='count'>
+<p>{{typeof count}} {{count}}</p>