Skip to content

Commit

Permalink
Fix x-on with both self and once (#4152)
Browse files Browse the repository at this point in the history
* Fix x-on with both self and once

* Fix x-on with both outside and once
  • Loading branch information
bb committed Apr 18, 2024
1 parent 8c8e71d commit 95ae590
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
17 changes: 9 additions & 8 deletions packages/alpinejs/src/utils/on.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ export default function on (el, event, modifiers, callback) {

if (modifiers.includes('prevent')) handler = wrapHandler(handler, (next, e) => { e.preventDefault(); next(e) })
if (modifiers.includes('stop')) handler = wrapHandler(handler, (next, e) => { e.stopPropagation(); next(e) })
if (modifiers.includes('self')) handler = wrapHandler(handler, (next, e) => { e.target === el && next(e) })

if (modifiers.includes("once")) {
handler = wrapHandler(handler, (next, e) => {
next(e);

listenerTarget.removeEventListener(event, handler, options);
});
}

if (modifiers.includes('away') || modifiers.includes('outside')) {
listenerTarget = document
Expand All @@ -57,13 +64,7 @@ export default function on (el, event, modifiers, callback) {
})
}

if (modifiers.includes('once')) {
handler = wrapHandler(handler, (next, e) => {
next(e)

listenerTarget.removeEventListener(event, handler, options)
})
}
if (modifiers.includes('self')) handler = wrapHandler(handler, (next, e) => { e.target === el && next(e) })

// Handle :keydown and :keyup listeners.
handler = wrapHandler(handler, (next, e) => {
Expand Down
40 changes: 40 additions & 0 deletions tests/cypress/integration/directives/x-on.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,27 @@ test('.self modifier',
}
)

test(
".self.once modifiers",
html`
<div x-data="{ foo: 'bar' }">
<h1 x-on:click.self.once="foo = 'baz'" id="selfTarget">
content
<button>click</button>
content
</h1>
<span x-text="foo"></span>
</div>
`,
({ get }) => {
get("span").should(haveText("bar"));
get("button").click();
get("span").should(haveText("bar"));
get("h1").click();
get("span").should(haveText("baz"));
}
);

test('.prevent modifier',
html`
<div x-data="{}">
Expand Down Expand Up @@ -492,6 +513,25 @@ test('@click.away',
}
)

test('@click.away.once works after clicking inside',
html`
<div x-data="{ foo: 'bar' }">
<h1 @click.away.once="foo = 'baz'">h1</h1>
<h2>h2</h2>
<span x-text="foo"></span>
</div>
`,
({ get }) => {
get('span').should(haveText('bar'))
get('h1').click()
get('span').should(haveText('bar'))
get('h2').click()
get('span').should(haveText('baz'))
}
)

test('@click.away with x-show (prevent race condition)',
html`
<div x-data="{ show: false }">
Expand Down

0 comments on commit 95ae590

Please sign in to comment.