Skip to content

Commit 5b4d77d

Browse files
authored
Attach hx-on handlers before processing nodes (#3131)
1 parent e7bb245 commit 5b4d77d

2 files changed

Lines changed: 69 additions & 35 deletions

File tree

src/htmx.js

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2905,46 +2905,52 @@ var htmx = (function() {
29052905
* @param {Element|HTMLInputElement} elt
29062906
*/
29072907
function initNode(elt) {
2908-
if (eltIsDisabled(elt)) {
2909-
cleanUpElement(elt)
2910-
return
2911-
}
2912-
// Ensure only valid Elements and not shadow DOM roots are inited
2913-
if (!(elt instanceof Element)) return
2914-
const nodeData = getInternalData(elt)
2915-
const attrHash = attributeHash(elt)
2916-
if (nodeData.initHash !== attrHash) {
2917-
// clean up any previously processed info
2918-
deInitNode(elt)
2919-
2920-
nodeData.initHash = attrHash
2908+
triggerEvent(elt, 'htmx:beforeProcessNode')
29212909

2922-
triggerEvent(elt, 'htmx:beforeProcessNode')
2923-
2924-
const triggerSpecs = getTriggerSpecs(elt)
2925-
const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs)
2910+
const nodeData = getInternalData(elt)
2911+
const triggerSpecs = getTriggerSpecs(elt)
2912+
const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs)
29262913

2927-
if (!hasExplicitHttpAction) {
2928-
if (getClosestAttributeValue(elt, 'hx-boost') === 'true') {
2929-
boostElement(elt, nodeData, triggerSpecs)
2930-
} else if (hasAttribute(elt, 'hx-trigger')) {
2931-
triggerSpecs.forEach(function(triggerSpec) {
2932-
// For "naked" triggers, don't do anything at all
2933-
addTriggerHandler(elt, triggerSpec, nodeData, function() {
2934-
})
2914+
if (!hasExplicitHttpAction) {
2915+
if (getClosestAttributeValue(elt, 'hx-boost') === 'true') {
2916+
boostElement(elt, nodeData, triggerSpecs)
2917+
} else if (hasAttribute(elt, 'hx-trigger')) {
2918+
triggerSpecs.forEach(function(triggerSpec) {
2919+
// For "naked" triggers, don't do anything at all
2920+
addTriggerHandler(elt, triggerSpec, nodeData, function() {
29352921
})
2936-
}
2922+
})
29372923
}
2924+
}
29382925

2939-
// Handle submit buttons/inputs that have the form attribute set
2940-
// see https://developer.mozilla.org/docs/Web/HTML/Element/button
2941-
if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) {
2942-
initButtonTracking(elt)
2943-
}
2926+
// Handle submit buttons/inputs that have the form attribute set
2927+
// see https://developer.mozilla.org/docs/Web/HTML/Element/button
2928+
if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) {
2929+
initButtonTracking(elt)
2930+
}
2931+
2932+
nodeData.firstInitCompleted = true
2933+
triggerEvent(elt, 'htmx:afterProcessNode')
2934+
}
29442935

2945-
nodeData.firstInitCompleted = true
2946-
triggerEvent(elt, 'htmx:afterProcessNode')
2936+
/**
2937+
* @param {Element} elt
2938+
* @returns {boolean}
2939+
*/
2940+
function maybeDeInitAndHash(elt) {
2941+
// Ensure only valid Elements and not shadow DOM roots are inited
2942+
if (!(elt instanceof Element)) {
2943+
return false
2944+
}
2945+
2946+
const nodeData = getInternalData(elt)
2947+
const hash = attributeHash(elt)
2948+
if (nodeData.initHash !== hash) {
2949+
deInitNode(elt)
2950+
nodeData.initHash = hash
2951+
return true
29472952
}
2953+
return false
29482954
}
29492955

29502956
/**
@@ -2960,9 +2966,23 @@ var htmx = (function() {
29602966
cleanUpElement(elt)
29612967
return
29622968
}
2963-
initNode(elt)
2964-
forEach(findElementsToProcess(elt), function(child) { initNode(child) })
2969+
2970+
const elementsToInit = []
2971+
if (maybeDeInitAndHash(elt)) {
2972+
elementsToInit.push(elt)
2973+
}
2974+
forEach(findElementsToProcess(elt), function(child) {
2975+
if (eltIsDisabled(child)) {
2976+
cleanUpElement(child)
2977+
return
2978+
}
2979+
if (maybeDeInitAndHash(child)) {
2980+
elementsToInit.push(child)
2981+
}
2982+
})
2983+
29652984
forEach(findHxOnWildcardElements(elt), processHxOnWildcard)
2985+
forEach(elementsToInit, initNode)
29662986
}
29672987

29682988
//= ===================================================================

test/attributes/hx-on-wildcard.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,20 @@ describe('hx-on:* attribute', function() {
133133
delete window.foo
134134
})
135135

136+
it('should fire when triggered by load', function() {
137+
this.server.respondWith('POST', '/test', 'test')
138+
make("<div hx-trigger='load' hx-post='/test' hx-on:htmx:config-request='foo = true'></div>")
139+
window.foo.should.equal(true)
140+
delete window.foo
141+
})
142+
143+
it('should fire when triggered by revealed', function() {
144+
this.server.respondWith('POST', '/test', 'test')
145+
make("<div hx-trigger='revealed' hx-post='/test' hx-on:htmx:config-request='foo = true' style='position: fixed; top: 1px; left: 1px; border: 3px solid red'></div>")
146+
window.foo.should.equal(true)
147+
delete window.foo
148+
})
149+
136150
it('de-initializes hx-on-* content properly', function() {
137151
window.tempCount = 0
138152
this.server.respondWith('POST', '/test', function(xhr) {

0 commit comments

Comments
 (0)