Open W1M0R opened 2 weeks ago
Seems that hx-on::load already does what you want fine for the simple case. Note that :htmx: can be shortened to :: making it only a few characters more than "hx-init"
<div hx-on::load="console.log('hi')"></div>
There are already many ways supported to handle load events in htmx like the htmx.onLoad() and hx-on and you can also try adding a simple event listener to the body so you don't have to define the load event on every single element.
document.body.addEventListener('htmx:load', function(evt) {
if(evt.detail.elt.tagName == 'TABLE') {
// do custom table init code here
}
});
One thing to be aware of with htmx:load events is they fire once on the body when you do the first full page load and also on every parent element swapped in via a htmx ajax request. But you do not get a load event for any children loaded in during initial page load or any children elements inside htmx partial responses. So sometimes when handling load events you may need to also process all the elt's children to see what needs to have custom init code run.
For example here is a global handler that could init all div's (swap in different logic for your use) as they are loaded:
function customInit(elt) {
console.log('do custom init here')
}
document.body.addEventListener('htmx:load', function(evt) {
if(evt.detail.elt.tagName == 'DIV') {
customInit(evt.detail.elt) // check item itself need init
}
for(const el of evt.detail.elt.querySelectorAll("div")) {
customInit(el) // check if any children need init
}
});
So if you were going to implement a proper "hx-init" attribute in htmx then it would be great if it was able to do the querySelectorAll part above for you and run reliably on all initial page loaded elements and all children of partial ajax responses. I think this could be done with a new htmx extension if you didn't want to have to write custom event listeners as above.
Thanks @MichaelWest22. Your example highlights some of my own observations very well. Maybe an extension could improve the situation. Looking at some of the htmx debug messages, maybe I can get something workable using: https://htmx.org/events/#htmx:afterProcessNode
I couldn't identify a simple enough htmx attribute or event that could satisfy this request.
For the time being, it looks like there is no equivalent capability in htmx (in terms of simplicity, safety, clarity, maintainability and LoB), when compared to the following initialisation methods offered by other supporting libraries:
<span _="init log 'hyperscript'"></span>
<span x-data x-init="console.log('alpine')"></span>
<span>
<script>
console.log("surreal");
</script>
</span>
<span hx-on:htmx:load="console.log('htmx - triggers for all htmx content or not at all')"></span>
<span
hx-get="/init-my-component"
hx-swap="none"
hx-trigger="load"
hx-on:my-component-init-event="console.log('htmx - server returns HX-Trigger my-component-init-event')"
></span>
The hx-trigger="load"
seems to execute as one would expect for initialisation. It looks like this method is then not the same as hx-on:htmx:load
(which executes sometimes or not at all according to its own rules).
For the hx-trigger
method to work without requiring server-side co-op, it would be helpful if the hx-trigger
could execute a custom event on load instead of executing the hx-get
. For example:
<span
hx-trigger="load trigger:my-init"
hx-on:my-init="console.log('body init (htmx)"
></span>
Here is the code handling the hx-trigger version of load
:
Yeah I can see several ways to create a hx-init extension:
let intAPI
htmx.defineExtension('hx-init', {
init: function(apiRef) {
intAPI = apiRef
},
onEvent: function(name, evt) {
if (name === 'htmx:load') {
if(evt.detail.elt.getAttribute('hx-init') !== null) {
intAPI.triggerEvent(evt.detail.elt,'htmx:init')
}
for(const el of evt.detail.elt.querySelectorAll("[hx-init]")) {
intAPI.triggerEvent(el,'htmx:init')
}
}
}
})
For example here is option 1 which seems to work well. just set hx-ext="hx-init" attribute on the page body and add hx-init="true" to all elements to trigger init on and then write a htmx:init eventListener
@MichaelWest22 I like option 1. Thanks for the reference implementation.
Thank you for providing a refreshing way to create for the web.
I find myself hooking into hyperscript and javascript whenever I need to do some initialisation work on an htmx component.
Hyperscript:
HTMX JS API:
I imagine
hx-on
could also be used, although I haven't tested it):It would be nice to have something similar for htmx, to avoid the need for hyperscript or javascript for that simple use case: