From 7e90aec0284eef89ad6eb0f7d3de60bd158add67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Thu, 31 Jan 2019 15:14:26 +0100 Subject: [PATCH] fix issue with subwidgets not being mounted/unmounted --- web/static/src/ts/core/Widget.ts | 15 ++++++++++++-- web/static/src/ts/core/qweb_vdom.ts | 2 +- web/static/src/ts/widgets/Action.ts | 4 ---- web/static/src/ts/widgets/Discuss.ts | 19 ++---------------- web/static/src/ts/widgets/clock.ts | 29 +++++++++++++++------------- web/static/tests/core/widget.test.ts | 4 ++++ 6 files changed, 36 insertions(+), 37 deletions(-) diff --git a/web/static/src/ts/core/Widget.ts b/web/static/src/ts/core/Widget.ts index 9164f9ee..e382d106 100644 --- a/web/static/src/ts/core/Widget.ts +++ b/web/static/src/ts/core/Widget.ts @@ -230,13 +230,24 @@ export class Widget { */ _mount(vnode: VNode, elm: HTMLElement): VNode { this.__widget__.vnode = patch(elm, vnode); + this.__mount(); + return this.__widget__.vnode; + } + + __mount() { + if (this.__widget__.isMounted) { + return; + } if (this.__widget__.parent) { - if (this.__widget__.parent.__widget__.isMounted) { + if (this.__widget__.parent!.__widget__.isMounted) { this.__widget__.isMounted = true; this.mounted(); + const children = this.__widget__.children; + for (let id in children) { + children[id].__mount(); + } } } - return this.__widget__.vnode; } private visitSubTree(callback: (w: Widget) => boolean) { diff --git a/web/static/src/ts/core/qweb_vdom.ts b/web/static/src/ts/core/qweb_vdom.ts index 11b371bd..2b2dc0b0 100644 --- a/web/static/src/ts/core/qweb_vdom.ts +++ b/web/static/src/ts/core/qweb_vdom.ts @@ -755,7 +755,7 @@ const widgetDirective: Directive = { ctx.addLine( `def${defID} = w${widgetID}.updateProps(${props}).then(()=>{let vnode=h(w${widgetID}.__widget__.vnode.sel, {key: ${templateID}});vnode.elm=w${widgetID}.el;c${ ctx.parentNode - }[_${dummyID}_index]=vnode;vnode.data.hook = {insert(a){a.elm.parentNode.replaceChild(w${widgetID}.el,a.elm);a.elm=w${widgetID}.el;},remove(){w${widgetID}.${ + }[_${dummyID}_index]=vnode;vnode.data.hook = {insert(a){a.elm.parentNode.replaceChild(w${widgetID}.el,a.elm);a.elm=w${widgetID}.el;w${widgetID}.__mount();},remove(){w${widgetID}.${ keepAlive ? "detach" : "destroy" }()}}});` ); diff --git a/web/static/src/ts/widgets/Action.ts b/web/static/src/ts/widgets/Action.ts index f442e978..e9427d02 100644 --- a/web/static/src/ts/widgets/Action.ts +++ b/web/static/src/ts/widgets/Action.ts @@ -11,10 +11,6 @@ export class Action extends Widget { template = `
`; currentWidget: any; - mounted() { - this.setContentWidget(); - } - shouldUpdate(nextProps: Props) { if (nextProps.stack !== this.props.stack) { this.props = nextProps; diff --git a/web/static/src/ts/widgets/Discuss.ts b/web/static/src/ts/widgets/Discuss.ts index 69ed1544..5f434a62 100644 --- a/web/static/src/ts/widgets/Discuss.ts +++ b/web/static/src/ts/widgets/Discuss.ts @@ -22,31 +22,16 @@ const template = ` - - -
`; -let n = 1; -class ChildWidget extends Widget { - name = "c"; - template = ``; - constructor(parent) { - super(parent); - this.state = { n }; - n++; - } -} - export class Discuss extends Widget { name = "discuss"; template = template; - widgets = { Clock, Counter, ColorWidget, ChildWidget }; - state = { validcounter: true, color: "red", test: [1, 2, 3] }; + widgets = { Clock, Counter, ColorWidget }; + state = { validcounter: true, color: "red" }; - mounted() {} resetCounter(ev: MouseEvent) { if (this.refs.counter instanceof Counter) { this.refs.counter.updateState({ counter: 3 }); diff --git a/web/static/src/ts/widgets/clock.ts b/web/static/src/ts/widgets/clock.ts index a0211a60..2d90ccf0 100644 --- a/web/static/src/ts/widgets/clock.ts +++ b/web/static/src/ts/widgets/clock.ts @@ -1,31 +1,34 @@ import { Widget } from "../core/widget"; import { Env } from "../env"; -const template = `
`; - export class Clock extends Widget { name = "clock"; - template = template; - interval: any | undefined; + template = `
`; + timeout: any | undefined; state = { currentTime: "" }; - async willStart() { - this.updateTime(); - } - mounted() { - this.interval = setInterval(this.updateTime.bind(this), 500); + this.updateTime(); + this.startClock(); } willUnmount() { - clearInterval(this.interval); + clearTimeout(this.timeout); } + updateTime() { - this.updateState({ - currentTime: new Date().toLocaleTimeString() - }); + this.updateState({ currentTime: new Date().toLocaleTimeString() }); + } + + startClock() { + const now = Date.now(); + const offset = 1000 - (now % 1000); + this.timeout = setTimeout(() => { + this.updateTime(); + this.startClock(); + }, offset); } } diff --git a/web/static/tests/core/widget.test.ts b/web/static/tests/core/widget.test.ts index 0bcedb65..4157ff9c 100644 --- a/web/static/tests/core/widget.test.ts +++ b/web/static/tests/core/widget.test.ts @@ -600,9 +600,13 @@ describe("composition", () => { expect(fixture.innerHTML).toBe( "
1
" ); + const counter = children(widget)[0]; + expect(counter.__widget__.isMounted).toBe(true); await widget.updateState({ ok: false }); expect(fixture.innerHTML).toBe("
"); + expect(counter.__widget__.isMounted).toBe(false); await widget.updateState({ ok: true }); + expect(counter.__widget__.isMounted).toBe(true); expect(fixture.innerHTML).toBe( "
1
" );