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 {
|
||||
|
|
|
@ -7,12 +7,23 @@ import widgetHbs from "discourse/widgets/hbs-compiler";
|
|||
import Widget from "discourse/widgets/widget";
|
||||
import ClassicComponent from "@ember/component";
|
||||
import RenderGlimmer from "discourse/widgets/render-glimmer";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
|
||||
class DemoWidget extends Widget {
|
||||
static actionTriggered = false;
|
||||
tagName = "div.my-widget";
|
||||
|
||||
html(attrs) {
|
||||
buildKey() {
|
||||
return "abc";
|
||||
}
|
||||
|
||||
defaultState() {
|
||||
return {
|
||||
actionTriggered: false,
|
||||
};
|
||||
}
|
||||
|
||||
html(attrs, state) {
|
||||
return [
|
||||
this.attach("button", {
|
||||
label: "rerender",
|
||||
|
@ -25,24 +36,29 @@ class DemoWidget extends Widget {
|
|||
hbs`<div class='glimmer-content'>
|
||||
arg1={{@data.arg1}} dynamicArg={{@data.dynamicArg}}
|
||||
</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,
|
||||
actionForComponentToTrigger: this.actionForComponentToTrigger,
|
||||
widgetActionTriggered: state.actionTriggered,
|
||||
}
|
||||
),
|
||||
];
|
||||
}
|
||||
dummyAction() {}
|
||||
|
||||
@bind
|
||||
actionForComponentToTrigger() {
|
||||
this.state.actionTriggered = true;
|
||||
DemoWidget.actionTriggered = true;
|
||||
this.scheduleRerender();
|
||||
}
|
||||
}
|
||||
|
||||
class DemoComponent extends ClassicComponent {
|
||||
static eventLog = [];
|
||||
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() {
|
||||
DemoComponent.eventLog.push("init");
|
||||
|
@ -231,6 +247,37 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
|
|||
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) {
|
||||
assert.throws(
|
||||
() => {
|
||||
|
|
Loading…
Reference in New Issue