diff --git a/src/htmx.js b/src/htmx.js index 5b6819642..26b62a75a 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -1622,6 +1622,7 @@ var htmx = (() => { // hx-on: binds to directly // hx-on:: is shorthand for hx-on:htmx: (htmx events) __handleHxOnAttributes(node) { + if (node._htmx?.onInitialized) return; let hxOnNames = this.__prefixes("hx-on"); let mc = this.config.metaCharacter || ':'; let handler = (code) => async (evt) => { @@ -1635,6 +1636,7 @@ var htmx = (() => { for (let attr of node.getAttributeNames()) { let prefix = hxOnNames.find(p => attr.startsWith(p)); if (!prefix) continue; + this.__htmxProp(node).onInitialized = true; let rest = attr.substring(prefix.length); let value = node.getAttribute(attr); // hx-on="click once -> doA(); blur -> doB()" diff --git a/test/tests/attributes/hx-on.js b/test/tests/attributes/hx-on.js index b2674d139..d81e55306 100644 --- a/test/tests/attributes/hx-on.js +++ b/test/tests/attributes/hx-on.js @@ -618,4 +618,26 @@ describe('hx-on="eventSpec -> code" syntax', function() { window.foo.should.equal(true); delete window.foo; }); + + it('calling process() multiple times does not duplicate hx-on listeners', function() { + window.fooCount = 0; + let btn = createProcessedHTML(''); + htmx.process(btn); + htmx.process(btn); + htmx.process(btn); + btn.click(); + window.fooCount.should.equal(1); + delete window.fooCount; + }); + + it('calling process() multiple times does not duplicate hx-on= listeners', function() { + window.fooCount = 0; + let btn = createProcessedHTML(''); + htmx.process(btn); + htmx.process(btn); + htmx.process(btn); + btn.click(); + window.fooCount.should.equal(1); + delete window.fooCount; + }); })