From cd9cac12461493d969e4d416f4e6252bc5ecf968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Tue, 30 Jul 2019 14:36:51 +0200 Subject: [PATCH] [REF] qweb: add forceUpdate method and make sure it only triggers an update once for multiple calls in same call stack --- src/qweb/qweb.ts | 18 ++++++++++++++++++ tests/component/component.test.ts | 2 +- tests/qweb/qweb.test.ts | 16 ++++++++++++++-- tools/playground/samples.js | 2 +- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/qweb/qweb.ts b/src/qweb/qweb.ts index 11417730..fac0fca5 100644 --- a/src/qweb/qweb.ts +++ b/src/qweb/qweb.ts @@ -163,6 +163,8 @@ export class QWeb extends EventBus { slots = {}; nextSlotId = 1; + isUpdating: boolean = false; + constructor(data?: string) { super(); if (data) { @@ -306,6 +308,22 @@ export class QWeb extends EventBus { return (result.elm).outerHTML; } + /** + * Force all widgets connected to this QWeb instance to rerender themselves. + * + * This method is mostly useful for external code that want to modify the + * application in some cases. For example, a router plugin. + */ + forceUpdate() { + this.isUpdating = true; + Promise.resolve().then(() => { + if (this.isUpdating) { + this.isUpdating = false; + this.trigger("update"); + } + }); + } + _compile(name: string, elem: Element, parentContext?: Context): CompiledTemplate { const isDebug = elem.attributes.hasOwnProperty("t-debug"); const ctx = new Context(name); diff --git a/tests/component/component.test.ts b/tests/component/component.test.ts index 1b1890e4..cb932cde 100644 --- a/tests/component/component.test.ts +++ b/tests/component/component.test.ts @@ -3539,7 +3539,7 @@ describe("environment and plugins", () => { env.someFlag = true; bus.on("some-event", null, () => { env.someFlag = !env.someFlag; - env.qweb.trigger("update"); + env.qweb.forceUpdate(); }); }; diff --git a/tests/qweb/qweb.test.ts b/tests/qweb/qweb.test.ts index 413339f0..459e181f 100644 --- a/tests/qweb/qweb.test.ts +++ b/tests/qweb/qweb.test.ts @@ -1,5 +1,5 @@ import { QWeb } from "../../src/qweb/index"; -import { normalize, renderToDOM, renderToString, trim } from "../helpers"; +import { normalize, renderToDOM, renderToString, trim, nextTick } from "../helpers"; //------------------------------------------------------------------------------ // Setup and helpers @@ -505,7 +505,7 @@ describe("t-call (template calling", () => { qweb.addTemplate("sub", "ok"); qweb.addTemplate("caller", '
'); const expected = "
ok
"; - expect(renderToString(qweb, "caller", {flag: true})).toBe(expected); + expect(renderToString(qweb, "caller", { flag: true })).toBe(expected); }); test("t-call not allowed on a non t node", () => { @@ -1178,3 +1178,15 @@ describe("debugging", () => { console.log = consoleLog; }); }); + +describe("update on event bus", () => { + test("two consecutive forceUpdates only causes one listener update", async () => { + const fn = jest.fn(); + qweb.on("update", null, fn); + qweb.forceUpdate(); + qweb.forceUpdate(); + expect(fn).toBeCalledTimes(0); + await nextTick(); + expect(fn).toBeCalledTimes(1); + }); +}); diff --git a/tools/playground/samples.js b/tools/playground/samples.js index 2cbacbf6..ca9411a2 100644 --- a/tools/playground/samples.js +++ b/tools/playground/samples.js @@ -953,7 +953,7 @@ function setupResponsivePlugin(env) { const updateEnv = owl.utils.debounce(() => { if (env.isMobile !== isMobile()) { env.isMobile = !env.isMobile; - env.qweb.trigger('update'); + env.qweb.forceUpdate(); } }, 15); window.addEventListener("resize", updateEnv);