DEV: Improve testing and documentation of RenderGlimmer actions (#18145)
This commit is contained in:
parent
3aaf4dcfd0
commit
4ccbb91691
|
@ -34,6 +34,44 @@ html(){
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also include function references in the `data` object, and use them as actions within the Ember component.
|
||||||
|
You will need to `bind` the function to ensure it maintains a reference to the widget, and you'll need to manually
|
||||||
|
call `this.scheduleRerender()` after making any changes to widget state (the normal widget auto-rerendering does not apply).
|
||||||
|
|
||||||
|
Note that the @bind decorator will only work if you're using class-based Widget syntax. When using createWidget, you'll need to
|
||||||
|
call `.bind(this)` manually when passing the function to RenderGlimmer.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
```
|
||||||
|
createWidget("my-widget", {
|
||||||
|
tagName: "div",
|
||||||
|
buildKey: () => `my-widget`,
|
||||||
|
|
||||||
|
defaultState() {
|
||||||
|
return { counter: 0 };
|
||||||
|
},
|
||||||
|
|
||||||
|
html(args, state){
|
||||||
|
return [
|
||||||
|
new RenderGlimmer(
|
||||||
|
this,
|
||||||
|
"div.my-wrapper-class",
|
||||||
|
hbs`<MyComponent @counter={{@data.counter}} @incrementCounter={{@data.incrementCounter}} />`,
|
||||||
|
{
|
||||||
|
counter: state.counter,
|
||||||
|
incrementCounter: this.incrementCounter.bind(this),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
incrementCounter() {
|
||||||
|
this.state.counter++;
|
||||||
|
this.scheduleRerender();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class RenderGlimmer {
|
export default class RenderGlimmer {
|
||||||
|
|
|
@ -7,12 +7,23 @@ import widgetHbs from "discourse/widgets/hbs-compiler";
|
||||||
import Widget from "discourse/widgets/widget";
|
import Widget from "discourse/widgets/widget";
|
||||||
import ClassicComponent from "@ember/component";
|
import ClassicComponent from "@ember/component";
|
||||||
import RenderGlimmer from "discourse/widgets/render-glimmer";
|
import RenderGlimmer from "discourse/widgets/render-glimmer";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
class DemoWidget extends Widget {
|
class DemoWidget extends Widget {
|
||||||
static actionTriggered = false;
|
static actionTriggered = false;
|
||||||
tagName = "div.my-widget";
|
tagName = "div.my-widget";
|
||||||
|
|
||||||
html(attrs) {
|
buildKey() {
|
||||||
|
return "abc";
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultState() {
|
||||||
|
return {
|
||||||
|
actionTriggered: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
html(attrs, state) {
|
||||||
return [
|
return [
|
||||||
this.attach("button", {
|
this.attach("button", {
|
||||||
label: "rerender",
|
label: "rerender",
|
||||||
|
@ -25,24 +36,29 @@ class DemoWidget extends Widget {
|
||||||
hbs`<div class='glimmer-content'>
|
hbs`<div class='glimmer-content'>
|
||||||
arg1={{@data.arg1}} dynamicArg={{@data.dynamicArg}}
|
arg1={{@data.arg1}} dynamicArg={{@data.dynamicArg}}
|
||||||
</div>
|
</div>
|
||||||
<DemoComponent @arg1={{@data.arg1}} @dynamicArg={{@data.dynamicArg}} @action={{@data.actionForComponentToTrigger}}/>`,
|
<DemoComponent @arg1={{@data.arg1}} @dynamicArg={{@data.dynamicArg}} @action={{@data.actionForComponentToTrigger}} @widgetActionTriggered={{@data.widgetActionTriggered}}/>`,
|
||||||
{
|
{
|
||||||
...attrs,
|
...attrs,
|
||||||
actionForComponentToTrigger: this.actionForComponentToTrigger,
|
actionForComponentToTrigger: this.actionForComponentToTrigger,
|
||||||
|
widgetActionTriggered: state.actionTriggered,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
dummyAction() {}
|
dummyAction() {}
|
||||||
|
|
||||||
|
@bind
|
||||||
actionForComponentToTrigger() {
|
actionForComponentToTrigger() {
|
||||||
|
this.state.actionTriggered = true;
|
||||||
DemoWidget.actionTriggered = true;
|
DemoWidget.actionTriggered = true;
|
||||||
|
this.scheduleRerender();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DemoComponent extends ClassicComponent {
|
class DemoComponent extends ClassicComponent {
|
||||||
static eventLog = [];
|
static eventLog = [];
|
||||||
classNames = ["demo-component"];
|
classNames = ["demo-component"];
|
||||||
layout = hbs`<DButton class="component-action-button" @label="component_action" @action={{@action}} />`;
|
layout = hbs`<DButton class="component-action-button" @label="component_action" @action={{@action}} /><p class='action-state'>{{@widgetActionTriggered}}</p>`;
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
DemoComponent.eventLog.push("init");
|
DemoComponent.eventLog.push("init");
|
||||||
|
@ -231,6 +247,37 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
|
||||||
assert.true(DemoWidget.actionTriggered, "widget event is triggered");
|
assert.true(DemoWidget.actionTriggered, "widget event is triggered");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("modify widget state with component action", async function (assert) {
|
||||||
|
await render(
|
||||||
|
hbs`<MountWidget @widget="demo-widget" @args={{hash arg1="val1"}} />`
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.false(
|
||||||
|
DemoWidget.actionTriggered,
|
||||||
|
"widget event has not been triggered yet"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
query(".action-state").innerText,
|
||||||
|
"false",
|
||||||
|
"eventTriggered is false in nested component"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.true(
|
||||||
|
exists("div.demo-component button"),
|
||||||
|
"component button is rendered"
|
||||||
|
);
|
||||||
|
|
||||||
|
await click("div.demo-component button");
|
||||||
|
assert.true(DemoWidget.actionTriggered, "widget event is triggered");
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
query(".action-state").innerText,
|
||||||
|
"true",
|
||||||
|
"eventTriggered is true in nested component"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test("developer ergonomics", function (assert) {
|
test("developer ergonomics", function (assert) {
|
||||||
assert.throws(
|
assert.throws(
|
||||||
() => {
|
() => {
|
||||||
|
|
Loading…
Reference in New Issue