diff --git a/packages/alpinejs/src/utils/dispatch.js b/packages/alpinejs/src/utils/dispatch.js index 26f198aef..297b74862 100644 --- a/packages/alpinejs/src/utils/dispatch.js +++ b/packages/alpinejs/src/utils/dispatch.js @@ -1,12 +1,14 @@ -export function dispatch(el, name, detail = {}) { - el.dispatchEvent( +export function dispatch(el, name, detail = {}, options = {}) { + return el.dispatchEvent( new CustomEvent(name, { detail, bubbles: true, // Allows events to pass the shadow DOM barrier. composed: true, cancelable: true, + // Allows overriding the default event options. + ...options }) ) } diff --git a/packages/docs/src/en/magics/dispatch.md b/packages/docs/src/en/magics/dispatch.md index e43f5ba04..9158ea59e 100644 --- a/packages/docs/src/en/magics/dispatch.md +++ b/packages/docs/src/en/magics/dispatch.md @@ -104,3 +104,42 @@ You can also use `$dispatch()` to trigger data updates for `x-model` data bindin ``` This opens up the door for making custom input components whose value can be set via `x-model`. + + +## Cancelable events + +You can use the returned value of `$dispatch` to check if the event was canceled or not. This is useful when you want to prevent the default behavior of an action. + +```alpine +
+
+ + + +
+

Hello

+
+
+
+``` + +This could be useful when you want to prevent opening/closing a modal or something like that by using event handlers. + + +## Overwriting options + +You can use the third parameter of `$dispatch` to overwrite the default options of the event. For example, you can set `bubbles` to `false`: + +```alpine + +
+ +
+ + +
+ +
+``` + +This is useful when you want to prevent the event from bubbling up to the parent elements. diff --git a/tests/cypress/integration/magics/$dispatch.spec.js b/tests/cypress/integration/magics/$dispatch.spec.js index b760be0b6..1c5107d26 100644 --- a/tests/cypress/integration/magics/$dispatch.spec.js +++ b/tests/cypress/integration/magics/$dispatch.spec.js @@ -14,3 +14,53 @@ test('$dispatch dispatches events properly', get('span').should(haveText('baz')) } ) + +test('$dispatch with bubbles overwrite to false shouldn\'t bubble (event handling on parent)', + html` +
+ + + +
+ `, + ({ get }) => { + get('span').should(haveText('bar')) + get('button').click() + get('span').should(haveText('bar')) + } +) + +test('$dispatch with bubbles overwrite to false shouldn\'t bubble (event handling on same element)', + html` +
+ + + +
+ `, + ({ get }) => { + get('span').should(haveText('bar')) + get('button').click() + get('span').should(haveText('baz')) + } +) + +test('$dispatch cancelable should be cancelable by $event.preventDefault()', + html` +
+ + + +
+ `, + ({ get }) => { + get('span').should(haveText('bar')) + get('button').click() + get('span').should(haveText('baz')) + } +)