Repository: sveltejs/svelte (JavaScript)
Date: 2017-04-11 13:39:03+00:00
Task type: Bug Fix

Issue:
multiple method calls with different argument sequence
Iterating through a matrix with nested loops (i, j), the same method gets called twice with the arguments swapped depending on their relative values [REPL](https://svelte.technology/repl?version=1.13.7&gist=8ff2f390bf1cf85804108243f7fdfb31). Extract below.

    {{#each triangularMatrix as ri, i}}
    <tr>
      {{#each triangularMatrix as rj, j}}
        {{#if i > j}}
          <td><input type="number" value={{ri[j]}} on:click='lowerThan(j, i)'></td>
        {{elseif i === j}}
          <td>1</td>
        {{else}}
          <td><input type="number" value={{rj[i]}} on:click='lowerThan(i, j)'></td>
        {{/if}}
      {{/each}}
    </tr>
    {{/each}}


the `lowerThan` function is called twice with the arguments swapped:
* if i < j, `<td ... on:click='lowerThan(i, j)` //correct
* if i > j, `<td ... on:click='lowerThan(j, i)` //always fails

In the generated code, a single change handler is registered and the arguments get swapped on the second call (ie the second assertion always fails).

The indices in the view are fine, the problem is only with the event handlers


Issue discussion:
I think I know what's going on here — two event handlers are being created, but they're both being given the name `click_handler` rather than `click_handler` and `click_handler_1`. Fairly sure I know how to fix that... on it



Solution patch:
diff --git a/src/generators/dom/visitors/Element/EventHandler.js b/src/generators/dom/visitors/Element/EventHandler.js
--- a/src/generators/dom/visitors/Element/EventHandler.js
+++ b/src/generators/dom/visitors/Element/EventHandler.js
@@ -44,7 +44,7 @@ export default function visitEventHandler ( generator, block, state, node, attri
 	// get a name for the event handler that is globally unique
 	// if hoisted, locally unique otherwise
 	const handlerName = shouldHoist ?
-		generator.alias( `${name}_handler` ) :
+		generator.getUniqueName( `${name}_handler` ) :
 		block.getUniqueName( `${name}_handler` );
 
 	// create the handler body


Test patch:
diff --git a/test/generator/samples/computed-empty/_config.js b/test/runtime/samples/computed-empty/_config.js
similarity index 100%
rename from test/generator/samples/computed-empty/_config.js
rename to test/runtime/samples/computed-empty/_config.js
diff --git a/test/generator/samples/computed-empty/main.html b/test/runtime/samples/computed-empty/main.html
similarity index 100%
rename from test/generator/samples/computed-empty/main.html
rename to test/runtime/samples/computed-empty/main.html
diff --git a/test/runtime/samples/event-handler-each-deconflicted/_config.js b/test/runtime/samples/event-handler-each-deconflicted/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/event-handler-each-deconflicted/_config.js
@@ -0,0 +1,36 @@
+export default {
+	data: {
+		foo: [ 1 ],
+		bar: [ 2 ],
+		clicked: 'neither'
+	},
+
+	html: `
+		<button>foo</button>
+		<button>bar</button>
+		<p>clicked: neither</p>
+	`,
+
+	test ( assert, component, target, window ) {
+		const buttons = target.querySelectorAll( 'button' );
+		const event = new window.MouseEvent( 'click' );
+
+		buttons[0].dispatchEvent( event );
+		assert.equal( component.get( 'clicked' ), 'foo' );
+		assert.htmlEqual( target.innerHTML, `
+			<button>foo</button>
+			<button>bar</button>
+			<p>clicked: foo</p>
+		` );
+
+		buttons[1].dispatchEvent( event );
+		assert.equal( component.get( 'clicked' ), 'bar' );
+		assert.htmlEqual( target.innerHTML, `
+			<button>foo</button>
+			<button>bar</button>
+			<p>clicked: bar</p>
+		` );
+
+		component.destroy();
+	}
+};
diff --git a/test/runtime/samples/event-handler-each-deconflicted/main.html b/test/runtime/samples/event-handler-each-deconflicted/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/event-handler-each-deconflicted/main.html
@@ -0,0 +1,9 @@
+{{#each foo as f}}
+	<button on:click='set({ clicked: "foo" })'>foo</button>
+{{/each}}
+
+{{#each bar as b}}
+	<button on:click='set({ clicked: "bar" })'>bar</button>
+{{/each}}
+
+<p>clicked: {{clicked}}</p>
\ No newline at end of file
diff --git a/test/generator/samples/observe-deferred/_config.js b/test/runtime/samples/observe-deferred/_config.js
similarity index 100%
rename from test/generator/samples/observe-deferred/_config.js
rename to test/runtime/samples/observe-deferred/_config.js
diff --git a/test/generator/samples/observe-deferred/main.html b/test/runtime/samples/observe-deferred/main.html
similarity index 100%
rename from test/generator/samples/observe-deferred/main.html
rename to test/runtime/samples/observe-deferred/main.html