DEV: Automatically re-render widget when arguments change (#22548)

In the past, widget implementors would have to subclass the MountWidget component and wire up `didUpdateAttrs` or an observer to trigger a re-render. If that wasn't done, then it could lead to weird behaviors, especially now that page transitions in Discourse do not de-render/re-render components by default.

This commit updates MountWidget so that it re-renders whenever any input arguments change.
This commit is contained in:
David Taylor 2023-07-12 10:22:42 +01:00 committed by GitHub
parent fb9948c79c
commit a68448d5cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 24 additions and 14 deletions

View File

@ -166,4 +166,8 @@ export default Component.extend({
unmountChildComponent(info) {
this._childComponents.removeObject(info);
},
didUpdateAttrs() {
this.queueRerender();
},
});

View File

@ -158,12 +158,6 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
);
await fillIn("input.dynamic-value-input", "somedynamicvalue");
assert.strictEqual(
query("div.glimmer-content").innerText,
"arg1=val1 dynamicArg=",
"changed arguments do not change before rerender"
);
await click(".my-widget button");
assert.strictEqual(
query("div.glimmer-content").innerText,
@ -200,16 +194,10 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
DemoComponent.eventLog = [];
await fillIn("input.dynamic-value-input", "somedynamicvalue");
assert.deepEqual(
DemoComponent.eventLog,
[],
"component is not notified of attr change before widget rerender"
);
await click(".my-widget button");
assert.deepEqual(
DemoComponent.eventLog,
["didReceiveAttrs"],
["didReceiveAttrs", "didReceiveAttrs"], // once for input, once for event
"component is notified of attr change during widget rerender"
);

View File

@ -1,6 +1,6 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, render } from "@ember/test-helpers";
import { click, render, settled } from "@ember/test-helpers";
import { count, exists, query } from "discourse/tests/helpers/qunit-helpers";
import { hbs } from "ember-cli-htmlbars";
import widgetHbs from "discourse/widgets/hbs-compiler";
@ -33,6 +33,24 @@ module("Integration | Component | Widget | base", function (hooks) {
assert.strictEqual(query(".test").innerText, "Hello Robin");
});
test("widget rerenders when args change", async function (assert) {
createWidget("hello-test", {
tagName: "div.test",
template: widgetHbs`Hello {{attrs.name}}`,
});
this.set("args", { name: "Robin" });
await render(hbs`<MountWidget @widget="hello-test" @args={{this.args}} />`);
assert.strictEqual(query(".test").innerText, "Hello Robin");
this.set("args", { name: "David" });
await settled();
assert.strictEqual(query(".test").innerText, "Hello David");
});
test("widget services", async function (assert) {
createWidget("service-test", {
tagName: "div.base-url-test",