Skip to content

Commit

Permalink
fix: always synchronously call bind:this (#12679)
Browse files Browse the repository at this point in the history
fixes #12673

#12591 wrongfully applied the "wrap in effect if an action on this element" logic for `bind:this`
  • Loading branch information
dummdidumm authored Jul 31, 2024
1 parent ccccac3 commit 01e7845
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changeset/smooth-pens-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: always synchronously call `bind:this`
Original file line number Diff line number Diff line change
Expand Up @@ -3164,16 +3164,15 @@ export const template_visitors = {
}

const parent = /** @type {import('#compiler').SvelteNode} */ (context.path.at(-1));
const has_action_directive =
parent.type === 'RegularElement' && parent.attributes.find((a) => a.type === 'UseDirective');

// Bindings need to happen after attribute updates, therefore after the render effect, and in order with events/actions.
// bind:this is a special case as it's one-way and could influence the render effect.
if (node.name === 'this') {
state.init.push(
b.stmt(has_action_directive ? b.call('$.effect', b.thunk(call_expr)) : call_expr)
);
state.init.push(b.stmt(call_expr));
} else {
const has_action_directive =
parent.type === 'RegularElement' &&
parent.attributes.find((a) => a.type === 'UseDirective');
state.after_update.push(
b.stmt(has_action_directive ? b.call('$.effect', b.thunk(call_expr)) : call_expr)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default test({
}

assert.deepEqual(value, [
'bind:this true',
'1',
'2',
'3',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,91 @@
<script>
import { onMount } from 'svelte';
export let value = [];
function one(elem) { elem.addEventListener('input', () => { value.push('1'); }); }
function four(elem) { elem.addEventListener('input', () => { value.push('4'); }); }
function eight(elem) { elem.addEventListener('input', () => { value.push('8'); }); }
function twelve(elem) { elem.addEventListener('input', () => { value.push('12'); }); }
function fifteen(elem) { elem.addEventListener('input', () => { value.push('15'); }); }
function seventeen(elem) { elem.addEventListener('input', () => { value.push('17'); }); }
function one(elem) {
elem.addEventListener('input', () => {
value.push('1');
});
}
function four(elem) {
elem.addEventListener('input', () => {
value.push('4');
});
}
function eight(elem) {
elem.addEventListener('input', () => {
value.push('8');
});
}
function twelve(elem) {
elem.addEventListener('input', () => {
value.push('12');
});
}
function fifteen(elem) {
elem.addEventListener('input', () => {
value.push('15');
});
}
function seventeen(elem) {
elem.addEventListener('input', () => {
value.push('17');
});
}
const foo = {
set two(v) { value.push('2'); },
set six(v) { value.push('6'); },
set nine(v) { value.push('9'); },
set eleven(v) { value.push('11'); },
set thirteen(v) { value.push('13'); },
set sixteen(v) { value.push('16'); },
set two(v) {
value.push('2');
},
set six(v) {
value.push('6');
},
set nine(v) {
value.push('9');
},
set eleven(v) {
value.push('11');
},
set thirteen(v) {
value.push('13');
},
set sixteen(v) {
value.push('16');
}
};
function three() {
value.push('3');
}
function five() {
value.push('5');
}
function seven() {
value.push('7');
}
function ten() {
value.push('10');
}
function fourteen() {
value.push('14');
}
function eighteen() {
value.push('18');
}
function three() { value.push('3'); }
function five() { value.push('5'); }
function seven() { value.push('7'); }
function ten() { value.push('10'); }
function fourteen() { value.push('14'); }
function eighteen() { value.push('18'); }
let el;
onMount(() => {
// ensure that bind:this doesn't influence the order of directives
// and isn't affected itself by an action being on the element
value.push('bind:this ' + !!el);
});
</script>

<input use:one bind:value={foo.two} on:input={three} />
<input use:four on:input={five} bind:value={foo.six} />
<input on:input={seven} use:eight bind:value={foo.nine} />
<input on:input={ten} bind:value={foo.eleven} use:twelve />
<input bind:value={foo.thirteen} on:input={fourteen} use:fifteen />
<input bind:value={foo.sixteen} use:seventeen on:input={eighteen} />
<input bind:this={el} bind:value={foo.sixteen} use:seventeen on:input={eighteen} />

0 comments on commit 01e7845

Please sign in to comment.