From 3cba111254deda97a423fbffec8a7ecb6113c7b9 Mon Sep 17 00:00:00 2001 From: tanhauhau Date: Sat, 11 Mar 2023 13:16:29 +0800 Subject: [PATCH] fix binding group with if block --- src/compiler/compile/render_dom/Block.ts | 2 +- src/compiler/compile/render_dom/Renderer.ts | 4 +- .../render_dom/wrappers/Element/Binding.ts | 18 ++++++--- src/runtime/internal/dom.ts | 2 +- .../_config.js | 39 +++++++++++++++++++ .../main.svelte | 14 +++++++ .../_config.js | 33 ++++++++++++++++ .../main.svelte | 14 +++++++ 8 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 test/runtime/samples/binding-input-group-if-gh-8372-1/_config.js create mode 100644 test/runtime/samples/binding-input-group-if-gh-8372-1/main.svelte create mode 100644 test/runtime/samples/binding-input-group-if-gh-8372-2/_config.js create mode 100644 test/runtime/samples/binding-input-group-if-gh-8372-2/main.svelte diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index c40dedc3b5..cb35673847 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -505,7 +505,7 @@ export default class Block { render_binding_groups() { for (const binding_group of this.binding_groups) { - binding_group.render(); + binding_group.render(this); } } } diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index ad2d1b092f..df1d68d5cb 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -27,8 +27,8 @@ export interface BindingGroup { contexts: string[]; list_dependencies: Set; keypath: string; - elements: Identifier[]; - render: () => void; + add_element: (block: Block, element: Identifier) => void; + render: (block: Block) => void; } export default class Renderer { diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index e48f3e0030..78417b61d8 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -153,7 +153,7 @@ export default class BindingWrapper { case 'group': { block.renderer.add_to_context('$$binding_groups'); - this.binding_group.elements.push(this.parent.var); + this.binding_group.add_element(block, this.parent.var); if ((this.parent as ElementWrapper).has_dynamic_value) { update_or_condition = (this.parent as ElementWrapper).dynamic_value_condition; @@ -321,7 +321,10 @@ function get_binding_group(renderer: Renderer, binding: BindingWrapper, block: B parent = parent.parent; } - const elements = []; + // when using bind:group with logic blocks, the with bind:group + // maybe scatter across different blocks + // will need to keep track all the elements that has the same bind:group within the same block + const elements = new Map(); contexts.forEach(context => { renderer.add_to_context(context, true); @@ -341,8 +344,13 @@ function get_binding_group(renderer: Renderer, binding: BindingWrapper, block: B contexts, list_dependencies, keypath, - elements, - render() { + add_element(block, element) { + if (!elements.has(block)) { + elements.set(block, []); + } + elements.get(block).push(element); + }, + render(block) { const local_name = block.get_unique_name('binding_group'); const binding_group = block.renderer.reference('$$binding_groups'); block.add_variable(local_name); @@ -360,7 +368,7 @@ function get_binding_group(renderer: Renderer, binding: BindingWrapper, block: B ); } block.chunks.hydrate.push( - b`${local_name}.p(${elements})` + b`${local_name}.p(${elements.get(block)})` ); block.chunks.destroy.push( b`${local_name}.r()` diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 70e7dcd7f8..ba2f4d4420 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -359,7 +359,7 @@ export function get_binding_group_value(group, __value, checked) { return Array.from(value); } -export function init_binding_group(group) { +export function init_binding_group(group: HTMLInputElement[]) { let _inputs: HTMLInputElement[]; return { /* push */ p(...inputs: HTMLInputElement[]) { diff --git a/test/runtime/samples/binding-input-group-if-gh-8372-1/_config.js b/test/runtime/samples/binding-input-group-if-gh-8372-1/_config.js new file mode 100644 index 0000000000..cdc6a488d0 --- /dev/null +++ b/test/runtime/samples/binding-input-group-if-gh-8372-1/_config.js @@ -0,0 +1,39 @@ +export default { + async test({ assert, target, component, window }) { + const button = target.querySelector('button'); + const clickEvent = new window.Event('click'); + const changeEvent = new window.Event('change'); + + const [input1, input2] = target.querySelectorAll('input[type="checkbox"]'); + function validate_inputs(v1, v2) { + assert.equal(input1.checked, v1); + assert.equal(input2.checked, v2); + } + + assert.deepEqual(component.test, []); + validate_inputs(false, false); + + component.test = ['a', 'b']; + validate_inputs(true, true); + + input1.checked = false; + await input1.dispatchEvent(changeEvent); + assert.deepEqual(component.test, ['b']); + + input2.checked = false; + await input2.dispatchEvent(changeEvent); + assert.deepEqual(component.test, []); + + input1.checked = true; + input2.checked = true; + await input1.dispatchEvent(changeEvent); + await input2.dispatchEvent(changeEvent); + assert.deepEqual(component.test, ['b', 'a']); + + await button.dispatchEvent(clickEvent); + + input1.checked = false; + await input1.dispatchEvent(changeEvent); + assert.deepEqual(component.test, []); + } +}; diff --git a/test/runtime/samples/binding-input-group-if-gh-8372-1/main.svelte b/test/runtime/samples/binding-input-group-if-gh-8372-1/main.svelte new file mode 100644 index 0000000000..71955b6b81 --- /dev/null +++ b/test/runtime/samples/binding-input-group-if-gh-8372-1/main.svelte @@ -0,0 +1,14 @@ + + + + + +{#if !hidden} + +{/if} + diff --git a/test/runtime/samples/binding-input-group-if-gh-8372-2/_config.js b/test/runtime/samples/binding-input-group-if-gh-8372-2/_config.js new file mode 100644 index 0000000000..69599885aa --- /dev/null +++ b/test/runtime/samples/binding-input-group-if-gh-8372-2/_config.js @@ -0,0 +1,33 @@ +export default { + async test({ assert, target, component, window }) { + const button = target.querySelector('button'); + const clickEvent = new window.Event('click'); + const changeEvent = new window.Event('change'); + + const [input1, input2] = target.querySelectorAll('input[type="radio"]'); + function validate_inputs(v1, v2) { + assert.equal(input1.checked, v1); + assert.equal(input2.checked, v2); + } + + component.test = 'a'; + validate_inputs(true, false); + + component.test = 'b'; + validate_inputs(false, true); + + input1.checked = true; + await input1.dispatchEvent(changeEvent); + assert.deepEqual(component.test, 'a'); + + input2.checked = true; + await input2.dispatchEvent(changeEvent); + assert.deepEqual(component.test, 'b'); + + await button.dispatchEvent(clickEvent); + + input1.checked = true; + await input1.dispatchEvent(changeEvent); + assert.deepEqual(component.test, 'a'); + } +}; diff --git a/test/runtime/samples/binding-input-group-if-gh-8372-2/main.svelte b/test/runtime/samples/binding-input-group-if-gh-8372-2/main.svelte new file mode 100644 index 0000000000..9add22cacc --- /dev/null +++ b/test/runtime/samples/binding-input-group-if-gh-8372-2/main.svelte @@ -0,0 +1,14 @@ + + + + + +{#if !hidden} + +{/if} +