Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 9 additions & 28 deletions src/htmx.js
Original file line number Diff line number Diff line change
Expand Up @@ -2637,27 +2637,6 @@ var htmx = (function() {

//= ===================================================================

/**
* @param {Element} elt
* @param {TriggerHandler} handler
* @param {HtmxNodeInternalData} nodeData
* @param {number} delay
*/
function loadImmediately(elt, handler, nodeData, delay) {
const load = function() {
if (!nodeData.loaded) {
nodeData.loaded = true
triggerEvent(elt, 'htmx:trigger')
handler(elt)
}
}
if (delay > 0) {
getWindow().setTimeout(load, delay)
} else {
load()
}
}

/**
* @param {Element} elt
* @param {HtmxNodeInternalData} nodeData
Expand Down Expand Up @@ -2724,9 +2703,10 @@ var htmx = (function() {
observer.observe(asElement(elt))
addEventListener(asElement(elt), handler, nodeData, triggerSpec)
} else if (!nodeData.firstInitCompleted && triggerSpec.trigger === 'load') {
if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) {
loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay)
}
triggerSpec.once = true
addEventListener(elt, handler, nodeData, triggerSpec)
// dispatch a custom non bubbling load event to just trigger the load
elt.dispatchEvent(new CustomEvent('load', { detail: { elt } }))
} else if (triggerSpec.pollInterval > 0) {
nodeData.polling = true
processPolling(asElement(elt), handler, triggerSpec)
Expand Down Expand Up @@ -3684,10 +3664,11 @@ var htmx = (function() {
/**
* @param {Element} elt
* @param {Element} target
* @param {string} prompt
* @param {string=} prompt
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this because prompt is optional as shown in if (prompt !== undefined)

* @param {Event=} event
* @returns {HtmxHeaderSpecification}
*/
function getHeaders(elt, target, prompt) {
function getHeaders(elt, target, prompt, event) {
/** @type HtmxHeaderSpecification */
const headers = {
'HX-Request': 'true',
Expand All @@ -3696,7 +3677,7 @@ var htmx = (function() {
'HX-Target': getAttributeValue(target, 'id'),
'HX-Current-URL': location.href
}
getValuesForElement(elt, 'hx-headers', false, headers)
getValuesForElement(elt, 'hx-headers', false, headers, event)
if (prompt !== undefined) {
headers['HX-Prompt'] = prompt
}
Expand Down Expand Up @@ -4420,7 +4401,7 @@ var htmx = (function() {
}
}

let headers = getHeaders(elt, target, promptResponse)
let headers = getHeaders(elt, target, promptResponse, event)

if (verb !== 'get' && !usesFormData(elt)) {
headers['Content-Type'] = 'application/x-www-form-urlencoded'
Expand Down
44 changes: 44 additions & 0 deletions test/attributes/hx-headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,48 @@ describe('hx-headers attribute', function() {
this.server.respond()
div.innerHTML.should.equal('Clicked!')
})

it('using js: with hx-headers has event available', function() {
this.server.respondWith('POST', '/vars', function(xhr) {
var headers = xhr.requestHeaders
headers.i1.should.equal('test')
xhr.respond(200, {}, 'Clicked!')
})

var div = make('<div id="test" hx-post="/vars" hx-headers="js:i1:event.target.id"></div>')
div.click()
this.server.respond()
div.innerHTML.should.equal('Clicked!')
})

it('using js: with hx-headers has event available on load event', function() {
this.server.respondWith('POST', '/vars', function(xhr) {
var headers = xhr.requestHeaders
headers.i1.should.equal('load')
xhr.respond(200, {}, 'Loaded!')
})

var div = make('<div id="test" hx-post="/vars" hx-headers="js:i1:event.type" hx-trigger="load"></div>')
this.server.respond()
div.innerHTML.should.equal('Loaded!')
})

it('using js: with hx-headers has event available on load event after swapping', function() {
this.server.respondWith('POST', '/vars', function(xhr) {
var headers = xhr.requestHeaders
headers.i1.should.equal('load')
xhr.respond(200, {}, '<div id="test2" hx-post="/vars2" hx-headers="js:i2:event.type" hx-trigger="load"></div>')
})
var div = make('<div id="test" hx-post="/vars" hx-headers="js:i1:event.type" hx-trigger="load" hx-swap="afterend"></div>')
this.server.respond()

this.server.respondWith('POST', '/vars2', function(xhr) {
var headers = xhr.requestHeaders
headers.i2.should.equal('load')
xhr.respond(200, {}, 'Nice!')
})
this.server.respond()
var test2 = byId('test2')
test2.innerHTML.should.equal("Nice!")
})
})
6 changes: 6 additions & 0 deletions www/content/attributes/hx-headers.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ If you wish for `hx-headers` to *evaluate* the values given, you can prefix the
<div hx-get="/example" hx-headers='js:{myVal: calculateValue()}'>Get Some HTML, Including a Dynamic Custom Header from Javascript in the Request</div>
```

When using evaluated code you can access the `event` object.

```html
<div hx-get="/example" hx-headers='js:{"hx-trigger-event": event.type}'>Get some HTML, including a custom header indicating which event triggered the request.</div>
```

## Security Considerations

* By default, the value of `hx-headers` must be valid [JSON](https://developer.mozilla.org/en-US/docs/Glossary/JSON).
Expand Down