diff --git a/docs/reference/actions.md b/docs/reference/actions.md index fad03108..1aad92a7 100644 --- a/docs/reference/actions.md +++ b/docs/reference/actions.md @@ -131,7 +131,7 @@ The list of supported modifier keys is shown below. Sometimes a controller needs to listen for events dispatched on the global `window` or `document` objects. -You can append `@window` or `@document` to the event name (along with any filter modifier) in an action descriptor to install the event listener on `window` or `document`, respectively, as in the following example: +You can append `@window` or `@document` to the event name (along with any filter modifer) in an action descriptor to install the event listener on `window` or `document`, respectively, as in the following example: @@ -215,12 +215,12 @@ route the event to the controller action, return `true`. The callback accepts a single object argument with the following keys: -Name | Description ---------|------------ -name | String: The option's name (`"open"` in the example above) -value | Boolean: The value of the option (`:open` would yield `true`, `:!open` would yield `false`) -event | [Event][]: The event instance -element | [Element]: The element where the action descriptor is declared +| Name | Description | +| ------- | ----------------------------------------------------------------------------------------------------- | +| name | String: The option's name (`"open"` in the example above) | +| value | Boolean: The value of the option (`:open` would yield `true`, `:!open` would yield `false`) | +| event | [Event][]: The event instance, including with the `params` action parameters on the submitter element | +| element | [Element]: The element where the action descriptor is declared | [toggle]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLDetailsElement/toggle_event [Event]: https://developer.mozilla.org/en-US/docs/web/api/event diff --git a/src/core/binding.ts b/src/core/binding.ts index bbaea3db..c349dc8f 100644 --- a/src/core/binding.ts +++ b/src/core/binding.ts @@ -29,8 +29,9 @@ export class Binding { } handleEvent(event: Event) { - if (this.willBeInvokedByEvent(event) && this.applyEventModifiers(event)) { - this.invokeWithEvent(event) + const actionEvent = this.prepareActionEvent(event) + if (this.willBeInvokedByEvent(event) && this.applyEventModifiers(actionEvent)) { + this.invokeWithEvent(actionEvent) } } @@ -65,12 +66,14 @@ export class Binding { return passes } - private invokeWithEvent(event: Event) { + private prepareActionEvent(event: Event): ActionEvent { + return Object.assign(event, { params: this.action.params }) + } + + private invokeWithEvent(event: ActionEvent) { const { target, currentTarget } = event try { - const { params } = this.action - const actionEvent: ActionEvent = Object.assign(event, { params }) - this.method.call(this.controller, actionEvent) + this.method.call(this.controller, event) this.context.logDebugActivity(this.methodName, { event, target, currentTarget, action: this.methodName }) } catch (error: any) { const { identifier, controller, element, index } = this diff --git a/src/tests/modules/core/event_options_tests.ts b/src/tests/modules/core/event_options_tests.ts index 403cb10a..e8323de7 100644 --- a/src/tests/modules/core/event_options_tests.ts +++ b/src/tests/modules/core/event_options_tests.ts @@ -213,6 +213,43 @@ export default class EventOptionsTests extends LogControllerTestCase { this.assertActions({ name: "log", eventType: "toggle" }) } + async "test custom action option callback event contains params"() { + let lastActionEventParams: Object = {} + + // clone the params to ensure we check the value as the callback receives it + // not the event after all actions have resolved + + const mockCallback = ({ event: { params = {} } = {} }) => { + lastActionEventParams = { ...params } + } + + this.application.registerActionOption("all", (options: Object) => { + mockCallback(options) + return true + }) + + this.buttonElement.setAttribute("data-c-custom-number-param", "41") + this.buttonElement.setAttribute("data-c-custom-string-param", "validation") + this.buttonElement.setAttribute("data-c-custom-boolean-param", "true") + this.buttonElement.setAttribute("data-d-should-ignore-param", "_IGNORED_") + + await this.setAction(this.buttonElement, "click->c#log:all") + + await this.triggerEvent(this.buttonElement, "click") + + this.assertActions({ name: "log", identifier: "c", eventType: "click", currentTarget: this.buttonElement }) + + const expectedEventParams = { + customBoolean: true, + customNumber: 41, + customString: "validation", + } + + this.assert.deepEqual(this.controllerConstructor.actionLog[0].params, expectedEventParams) + + this.assert.deepEqual(lastActionEventParams, expectedEventParams) + } + setAction(element: Element, value: string) { element.setAttribute("data-action", value) return this.nextFrame