Open sbrow opened 1 year ago
I'm also new to htmx, but wanted to chime in with some observations:
edit: an alternative solution would be to manually trigger the load event from jQuery:
$(document).ready(() => htmx.trigger('#my-form', 'htmx:load'));
@danielvaughn Thanks for the input!
- According to the documentation, the load event is fired after a new node is added to the dom. So my expectation would be that it wouldn't fire on document load, though I could easily see myself assuming the same.
That is a valid point, I think the functionality I'm looking for could easily be added as a separate event. htmx:init
perhaps? More to the point though, in my experience returning HTML via ajax, often if you need to run a script for a DOM node when the page loads, there's a pretty good chance you'll also need to run that code if you inject that node into the page after its loaded.
- I assume the source of this json string is some kind of history stored on the client, right?
Not in my case. Here I have an "export resource" button that makes a POST request to the server that returns a Bootstrap modal that gets added to the bottom of the page. The javascript for the modal needs to be triggered in order for it to appear with the proper animation. On another note, the whole idea here (for me anyway) is to eliminate the need for JSON and javascript as much as possible, i.e. HATEOAS.
- Naive question - when you say "htmx returns that form", is it possible to pass the inserted values to the server so that htmx can return them along with the form? That way you can use jQuery's document load event to load the initial values and let htmx take over after that.
Not sure I understand what you mean here. I am passing all the relevant information to the server in the hx-post
ajax request, and the server returns the html fragment that I need to add to the page. We're not doing a full page load here, which again is kinda the point of htmx, so unless I'm a complete idiot, (always a possibility) and $(document).ready(...)
triggers when new nodes are added to the DOM, I don't think this will work for me.
- Naive question - when you say "htmx returns that form", is it possible to pass the inserted values to the server so that htmx can return them along with the form? That way you can use jQuery's document load event to load the initial values and let htmx take over after that.
I think I should perhaps go into more depth here.
Elaborating on my example, we need to run the following function whenever our modal component is added to the page, or after an initial page load if the component is already there:
function setupModal() {
(new bootstrap.Modal('#myModal', options)).show();
}
If the modal is on the page during the initial page load, then you are 100% correct that we can use $(document).ready(setupModal)
to set it up. If the modal only appears in the response from an htmx request, then we can add hx-on::load="setupModal"
to the root node in the response and it will work fine.
Now, we also have a special autofilling input that we need to setup with this code:
function setupInput(selector) {
$(selector).autofillInput();
}
I could call setupInput()
at the end of the the setupModal
function, but then I've tightly coupled two unrelated components. Usage of the quickfill component isn't mutually inclusive with usage of the modal. So what I ended up doing was something akin to hx-on::load="setupModal(); setupInput()"
which feels messy.
What I would prefer is something like this:
<input name="quickfill" hx-on::init="$(this).autofillInput()" />
This way, the code to initialize the component is located as close to where it is used as possible, and I don't need to worry about which node is the root node and whether or not I need to add my input setup code to the htmx-load
handler of that node.
I feel it would be a better DX if we could rely on
htmx:load
to fire:
- On any element present in the DOM when the page "loads"
- On any root element that is inserted into the DOM after an ajax request (the way it functions now) and
- On any child element(s) that are inserted into the DOM after an ajax request.
I support that notion! In my particular case, I'd like to declaratively define the initializer on my lazy-loaded content like I understand @sbrow describes in the following:
If the modal only appears in the response from an htmx request, then we can add
hx-on::load="setupModal"
to the root node in the response and it will work fine.
But that doesn't seem to work at the moment, does it? Strangely, if you set up a logger you see that the corresponding htmx:load
event seems to be triggered - yet the handler isn't called. See https://jsfiddle.net/0fuetpr8/1/ .
Please note that I'm also new to this awesome library and am learning the ropes. If there's another mechanism that I can use to achieve this (while maintaining above-mentioned Locality of Behaviour) but am unaware of, please point me in the right direction! My vision may be clouded by years of using a custom library for AJAX requests that takes a similar declarative approach using HTML data-
attributes.
Hi @sbrow,
I just wanted to say, that I totally support your idea about hx-on::load
. I am struggling the same way. Sometimes you I would like to register / unregister javascript if a element is loaded.
The Problem
When I first saw the
hx-on::load
attribute, I immediately thought of thex-init
attribute from Alpine.js. Therefore, It was quite a surprise to to learn that not only does thehtmx:load
event not get fired on elements that are present during the initial page load (at least in my experience, see #1500), but it only triggers on the outermost element(s?) that was/were inserted.I found this particularly shocking because of the Locality of Behaviour discussion on htmx.org.
My use case
I have a jQuery based input component that takes a base64 encoded JSON string and uses its values to autofill the rest of the form. So every time htmx returns that form, it needs to call code to set up the input.
Now I could just use Alpine.js, (or Hyperscript), but the site I'm working on already has jQuery installed, and it seems silly (and needlessly confusing) to add another js framework to the stack just to set up one event handler.
I ended up just adding
$(document).on("DOMNodeInserted", setup);
to my javascript code, but since that demonstrates poor LoB, it'd be nice to have something more seamless.Solution
I am new to htmx, and I apologize if I'm being a complete idiot here, but because of my experience with Alpine.js and Livewire (in many ways an inferior
htmx
) I feel it would be a better DX if we could rely onhtmx:load
to fire:Let me know what you think.
P.S. Thank you for bringing this awesome library to the world! I think it's going to solve a lot of headaches for me and many others. :heart:
P.P.S To anyone else with this problem, the following un-optimized code might solve your woes.