fix bind:group contextual reference (#5199)

pull/5210/head
Tan Li Hau 4 years ago committed by GitHub
parent 3dad14f0e1
commit 02e10b1159
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,6 +6,7 @@
* Fix reactivity when passing `$$props` to a `<slot>` ([#3364](https://github.com/sveltejs/svelte/issues/3364))
* Fix unneeded invalidation of `$$props` and `$$restProps` ([#4993](https://github.com/sveltejs/svelte/issues/4993), [#5118](https://github.com/sveltejs/svelte/issues/5118))
* Provide better compiler error message when mismatched tags are due to autoclosing of tags ([#5049](https://github.com/sveltejs/svelte/issues/5049))
* Fix `bind:group` when using contextual reference ([#5174](https://github.com/sveltejs/svelte/issues/5174))
## 3.24.0

@ -41,7 +41,8 @@ export default class Binding extends Node {
this.raw_expression = JSON.parse(JSON.stringify(info.expression));
const { name } = get_object(this.expression.node);
this.is_contextual = scope.names.has(name);
this.is_contextual = Array.from(this.expression.references).some(name => scope.names.has(name));
// make sure we track this as a mutable ref
if (scope.is_let(name)) {
@ -49,7 +50,7 @@ export default class Binding extends Node {
code: 'invalid-binding',
message: 'Cannot bind to a variable declared with the let: directive'
});
} else if (this.is_contextual) {
} else if (scope.names.has(name)) {
if (scope.is_await(name)) {
component.error(this, {
code: 'invalid-binding',

@ -24,7 +24,7 @@ export default class Expression {
component: Component;
owner: Owner;
node: any;
references: Set<string>;
references: Set<string> = new Set();
dependencies: Set<string> = new Set();
contextual_dependencies: Set<string> = new Set();
@ -50,7 +50,7 @@ export default class Expression {
this.template_scope = template_scope;
this.owner = owner;
const { dependencies, contextual_dependencies } = this;
const { dependencies, contextual_dependencies, references } = this;
let { map, scope } = create_scopes(info);
this.scope = scope;
@ -75,6 +75,7 @@ export default class Expression {
if (is_reference(node, parent)) {
const { name, nodes } = flatten_reference(node);
references.add(name);
if (scope.has(name)) return;

@ -2,7 +2,6 @@ import EachBlock from "../../../nodes/EachBlock";
import InlineComponentWrapper from "../InlineComponent";
import ElementWrapper from "../Element";
import Binding from "../../../nodes/Binding";
import get_object from "../../../utils/get_object";
export default function mark_each_block_bindings(
parent: ElementWrapper | InlineComponentWrapper,
@ -10,9 +9,12 @@ export default function mark_each_block_bindings(
) {
// we need to ensure that the each block creates a context including
// the list and the index, if they're not otherwise referenced
const object = get_object(binding.expression.node).name;
const each_block = parent.node.scope.get_owner(object);
(each_block as EachBlock).has_binding = true;
binding.expression.references.forEach(name => {
const each_block = parent.node.scope.get_owner(name);
if (each_block) {
(each_block as EachBlock).has_binding = true;
}
});
if (binding.name === "group") {
// for `<input bind:group={} >`, we make sure that all the each blocks creates context with `index`

@ -0,0 +1,87 @@
export default {
html: `
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p></p>
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p></p>
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p></p>
`,
async test({ assert, component, target, window }) {
const inputs = target.querySelectorAll('input');
assert.equal(inputs[0].checked, false);
assert.equal(inputs[1].checked, false);
assert.equal(inputs[2].checked, false);
assert.equal(inputs[3].checked, false);
assert.equal(inputs[4].checked, false);
assert.equal(inputs[5].checked, false);
assert.equal(inputs[6].checked, false);
assert.equal(inputs[7].checked, false);
assert.equal(inputs[8].checked, false);
const event = new window.Event('change');
inputs[2].checked = true;
await inputs[2].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p>z</p>
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p></p>
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p></p>
`);
inputs[4].checked = true;
await inputs[4].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p>z</p>
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p>y</p>
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p></p>
`);
inputs[5].checked = true;
await inputs[5].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p>z</p>
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p>y, z</p>
<label><input type="checkbox" value="x"> x</label>
<label><input type="checkbox" value="y"> y</label>
<label><input type="checkbox" value="z"> z</label>
<p></p>
`);
}
};

@ -0,0 +1,22 @@
<script>
const values = ['x', 'y', 'z'];
const list = {
a: [],
b: [],
c: [],
};
</script>
{#each Object.keys(list) as key}
{#each values as value}
<label>
<input
type='checkbox'
bind:group={list[key]}
value={value}
/>
{value}
</label>
{/each}
<p>{list[key].join(', ')}</p>
{/each}
Loading…
Cancel
Save