Repository: sveltejs/svelte (JavaScript)
Date: 2017-04-16 18:22:05+00:00
Task type: Bug Fix

Issue:
7guis example broken
Still trying to figure out exactly why, but adjusting the diameter in the 7guis circles example (click to create a circle, right-click to bring up the adjuster dialog) is broken:

* [1.13.6](https://svelte.technology/repl?version=1.13.6&example=7guis-circles) (works)
* [1.13.7](https://svelte.technology/repl?version=1.13.7&example=7guis-circles) (broken)
7guis example broken
Still trying to figure out exactly why, but adjusting the diameter in the 7guis circles example (click to create a circle, right-click to bring up the adjuster dialog) is broken:

* [1.13.6](https://svelte.technology/repl?version=1.13.6&example=7guis-circles) (works)
* [1.13.7](https://svelte.technology/repl?version=1.13.7&example=7guis-circles) (broken)


Issue discussion:
It looks like this has to do with a single input element with both a `bind:` directive and an `on:` directive for the same event that calls `component.set`. A simple reproduction:

```html
<input bind:value='a' on:input='set({ b: 0 })'>
```

When an `input` event comes in, the `on:input` handler is called first. This eventually calls `_fragment.update` with the whole new state, which includes the _old_ value for `a`. The input element is set back to its old value, and then when we get into the other event handler for the `bind:value`, when we look at `.value` it has the old value in it again.

Having the event handler for the `bind:` attached first so that it is run before the event handler for the `on:` is run seems to address this specific issue, but I don't know whether that is in general a solution or something we want to do.

_Edit:_ Is there a particular reason for the ordering given [here](https://github.com/sveltejs/svelte/blob/master/src/generators/dom/visitors/Element/Element.js#L14)? From a brief test, swapping the `Binding` and `EventHandler` in the ordering looks like it takes care of this.
It looks like this has to do with a single input element with both a `bind:` directive and an `on:` directive for the same event that calls `component.set`. A simple reproduction:

```html
<input bind:value='a' on:input='set({ b: 0 })'>
```

When an `input` event comes in, the `on:input` handler is called first. This eventually calls `_fragment.update` with the whole new state, which includes the _old_ value for `a`. The input element is set back to its old value, and then when we get into the other event handler for the `bind:value`, when we look at `.value` it has the old value in it again.

Having the event handler for the `bind:` attached first so that it is run before the event handler for the `on:` is run seems to address this specific issue, but I don't know whether that is in general a solution or something we want to do.

_Edit:_ Is there a particular reason for the ordering given [here](https://github.com/sveltejs/svelte/blob/master/src/generators/dom/visitors/Element/Element.js#L14)? From a brief test, swapping the `Binding` and `EventHandler` in the ordering looks like it takes care of this.

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
@@ -13,8 +13,8 @@ const meta = {
 
 const order = {
 	Attribute: 1,
-	EventHandler: 2,
-	Binding: 3,
+	Binding: 2,
+	EventHandler: 3,
 	Ref: 4
 };
 


Test patch:
diff --git a/test/runtime/samples/binding-input-with-event/_config.js b/test/runtime/samples/binding-input-with-event/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/binding-input-with-event/_config.js
@@ -0,0 +1,20 @@
+export default {
+	data: {
+		a: 42
+	},
+
+	test ( assert, component, target, window ) {
+		const input = target.querySelector( 'input' );
+		assert.equal( input.value, '42' );
+
+		const event = new window.Event( 'input' );
+
+		input.value = 43;
+		input.dispatchEvent( event );
+
+		assert.equal( input.value, '43' );
+		assert.equal( component.get( 'a' ), 43 );
+
+		component.destroy();
+	}
+};
diff --git a/test/runtime/samples/binding-input-with-event/main.html b/test/runtime/samples/binding-input-with-event/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/binding-input-with-event/main.html
@@ -0,0 +1 @@
+<input bind:value='a' on:input='set({ b: 0 })'>
\ No newline at end of file