diff --git a/README.md b/README.md index 761d5b5b..f622f6be 100644 --- a/README.md +++ b/README.md @@ -182,3 +182,6 @@ We have 3 main folders and 3 main files: - check if it is possible to remove parent reference in widget - default implementation of propsUpdated? + +- **Rendering** think about batching all patching updates in a + nextanimationframe diff --git a/web/static/src/ts/core/Widget.ts b/web/static/src/ts/core/Widget.ts index 82c6ad1a..da77c362 100644 --- a/web/static/src/ts/core/Widget.ts +++ b/web/static/src/ts/core/Widget.ts @@ -26,6 +26,7 @@ interface Meta { parent: Widget | null; children: { [key: number]: Widget }; // children mapping: from templateID to widgetID + // should it be a map number => Widget? cmap: { [key: number]: number }; } diff --git a/web/static/src/ts/core/qweb_vdom.ts b/web/static/src/ts/core/qweb_vdom.ts index 39622516..917de500 100644 --- a/web/static/src/ts/core/qweb_vdom.ts +++ b/web/static/src/ts/core/qweb_vdom.ts @@ -715,16 +715,16 @@ const widgetDirective: Directive = { ctx.addLine(`let _${dummyID}_index = c${ctx.parentNode}.length;`); ctx.addLine(`c${ctx.parentNode}.push(_${dummyID});`); ctx.addLine(`let def${defID};`); + ctx.addLine( + `let w${widgetID} = ${widgetID} in context.__widget__.cmap ? context.__widget__.children[context.__widget__.cmap[${widgetID}]] : false;` + ); - ctx.addLine(`if (${widgetID} in context.__widget__.cmap) {`); + ctx.addLine(`if (w${widgetID}) {`); ctx.indent(); ctx.addLine( - `let curWidget = context.__widget__.children[context.__widget__.cmap[${widgetID}]]` - ); - ctx.addLine( - `def${defID} = curWidget.updateProps(${props}).then(()=>{vnode=curWidget.__widget__.vnode;c${ + `def${defID} = w${widgetID}.updateProps(${props}).then(()=>{vnode=w${widgetID}.__widget__.vnode;c${ ctx.parentNode - }[_${dummyID}_index]=vnode;vnode.data.hook = {remove(){curWidget.destroy()}}});` + }[_${dummyID}_index]=vnode;vnode.data.hook = {remove(){w${widgetID}.destroy()}}});` ); ctx.dedent(); ctx.addLine("} else {"); @@ -734,7 +734,7 @@ const widgetDirective: Directive = { `let _${widgetID} = new context.widgets['${value}'](owner, ${props});` ); ctx.addLine( - `context.__widget__.cmap[${widgetID}] = _${widgetID}.__widget__.id` + `context.__widget__.cmap[${widgetID}] = _${widgetID}.__widget__.id;` ); ctx.addLine( `def${defID} = _${widgetID}._start().then(() => _${widgetID}._render()).then(vnode=>{c${ diff --git a/web/static/tests/core/widget.test.ts b/web/static/tests/core/widget.test.ts index 28b171b0..a7a9fc5f 100644 --- a/web/static/tests/core/widget.test.ts +++ b/web/static/tests/core/widget.test.ts @@ -535,6 +535,30 @@ describe("composition", () => { "
1
" ); }); + + test("sub widgets are destroyed if no longer in dom, then recreated", async () => { + class ParentWidget extends Widget { + name = "a"; + state = { ok: true }; + template = ` +
`; + widgets = { counter: Counter }; + } + const widget = new ParentWidget(env); + await widget.mount(fixture); + const button = fixture.getElementsByTagName("button")[0]; + await button.click(); + await nextTick(); + expect(fixture.innerHTML).toBe( + "
1
" + ); + await widget.updateState({ ok: false }); + expect(fixture.innerHTML).toBe("
"); + await widget.updateState({ ok: true }); + expect(fixture.innerHTML).toBe( + "
0
" + ); + }); }); describe("props evaluation (with t-props directive)", () => {