diff --git a/src/compile/render-dom/wrappers/Element/index.ts b/src/compile/render-dom/wrappers/Element/index.ts index 5f6f94f38b..0c2904695d 100644 --- a/src/compile/render-dom/wrappers/Element/index.ts +++ b/src/compile/render-dom/wrappers/Element/index.ts @@ -282,11 +282,6 @@ export default class ElementWrapper extends Wrapper { }); } - const eventHandlerOrBindingUsesComponent = ( - this.bindings.length > 0 || - this.node.handlers.some(handler => handler.usesComponent) - ); - const eventHandlerOrBindingUsesContext = ( this.bindings.some(binding => binding.node.usesContext) || this.node.handlers.some(handler => handler.usesContext) || @@ -534,17 +529,46 @@ export default class ElementWrapper extends Wrapper { renderer.component.declarations.push(name); renderer.component.template_references.add(name); - const { handler, object } = this_binding.munge(block); + const munged = this_binding.munge(block); + const { handler, object } = munged; - renderer.component.partly_hoisted.push(deindent` - function ${name}($$node) { - ${handler.mutation} - $$invalidate('${object}', ${object}); - } - `); + // TODO this really is spectacularly confusing, + // the whole mess needs cleaning up + const contextual_dependencies = new Set(); + addToSet(contextual_dependencies, munged.contextual_dependencies); + addToSet(contextual_dependencies, handler.contextual_dependencies); + + let fn; + + if (contextual_dependencies.size > 0) { + block.builders.init.addBlock(deindent` + function ${name}() { + ctx.${name}(${this.var}, ctx); + } + `); + + fn = deindent` + function ${name}($$node, { ${[...contextual_dependencies].join(', ')} }) { + ${handler.mutation} + $$invalidate('${object}', ${object}); + } + `; + + block.builders.mount.addLine(`@add_binding_callback(${name});`); + block.builders.destroy.addLine(`ctx.${name}(null, ctx);`); + } else { + fn = deindent` + function ${name}($$node) { + ${handler.mutation} + $$invalidate('${object}', ${object}); + } + `; + + block.builders.mount.addLine(`@add_binding_callback(() => ctx.${name}(${this.var}));`); + block.builders.destroy.addLine(`ctx.${name}(null);`); + } - block.builders.mount.addLine(`@add_binding_callback(() => ctx.${name}(${this.var}));`); - block.builders.destroy.addLine(`ctx.${name}(null);`); + renderer.component.partly_hoisted.push(fn); } } diff --git a/test/runtime/samples/binding-this-contextual/_config.js b/test/runtime/samples/binding-this-contextual/_config.js new file mode 100644 index 0000000000..208cd5e40e --- /dev/null +++ b/test/runtime/samples/binding-this-contextual/_config.js @@ -0,0 +1,42 @@ +export default { + props: { + items: ['a', 'b', 'c'] + }, + + html: ` +
a
+
b
+
c
+ `, + + test({ assert, component, target }) { + let nodes = [...target.querySelectorAll('div')]; + assert.deepEqual(component.nodes, nodes); + + console.group('setting b, c, d, e'); + component.items = ['b', 'c', 'd', 'e']; + console.groupEnd(); + + assert.htmlEqual(target.innerHTML, ` +
b
+
c
+
d
+
e
+ `); + + nodes = [...target.querySelectorAll('div')]; + assert.deepEqual(component.nodes, nodes); + + console.group('setting c, d'); + component.items = ['c', 'd']; + console.groupEnd(); + + assert.htmlEqual(target.innerHTML, ` +
c
+
d
+ `); + + nodes = [...target.querySelectorAll('div')]; + assert.deepEqual(component.nodes, [...nodes, null, null]); + } +}; diff --git a/test/runtime/samples/binding-this-contextual/main.html b/test/runtime/samples/binding-this-contextual/main.html new file mode 100644 index 0000000000..9692e8311c --- /dev/null +++ b/test/runtime/samples/binding-this-contextual/main.html @@ -0,0 +1,8 @@ + + +{#each items as item, i (item)} +
{item}
+{/each} \ No newline at end of file