bigskysoftware / htmx

</> htmx - high power tools for HTML
https://htmx.org
Other
38.19k stars 1.3k forks source link

Need to add a fake hx-post to a form to prevent it submitting by default #2323

Open reubenfirmin opened 8 months ago

reubenfirmin commented 8 months ago

When I have focus in the text input and press enter to submit, two requests are made; one to / (there's no action on the form) and one to /ingredients/tags/edit.

<form id="tagsForm">

<input type="hidden" name="id" value="4178f523-5e1c-4fc8-9961-307a416e40c5">
<input type="hidden" name="recipe" value="false">

    <div class="relative">

<input class="..." type="text" id="tagInput" hx-trigger="keypress[code=='Enter']" hx-put="/ingredients/tags/edit" hx-swap="innerHTML" name="tags" value="veg" placeholder="Enter tags separated by comma" required="required">

<button class="..." type="button" hx-trigger="click" hx-put="/ingredients/tags/edit?" hx-swap="innerHTML" hx-include="#tagsForm">Save</button>

</div>
  </form>

If I instead put a dummy hx-post on the form, only the input's submit actually takes place (which is what I want). I suppose I can probably lift the common hx-put to the form as an alternative, but I do think it's a bug that this occurs.

<form id="tagsForm" hx-post="/submit">

<input type="hidden" name="id" value="4178f523-5e1c-4fc8-9961-307a416e40c5">
<input type="hidden" name="recipe" value="false">

    <div class="relative">
<input class="..." type="text" id="tagInput" hx-trigger="keypress[code=='Enter']" hx-put="/ingredients/tags/edit" hx-swap="innerHTML" name="tags" value="veg" placeholder="Enter tags separated by comma" required="required">

<button class="..." type="button" hx-trigger="click" hx-put="/ingredients/tags/edit?" hx-swap="innerHTML" hx-include="#tagsForm">Save</button>
</div>
  </form>
andryyy commented 8 months ago

That’s the natural event of the form, which is also not handled by HTMX. It is submitting due to event bubbling.

The proper way would indeed be to put the hx- stuff (of the button) into the form, change the type of that button to "submit" and perhaps add a hx-trigger="submit“ to it or "click from:[type=submit]".

reubenfirmin commented 8 months ago

Shouldn't the hx-trigger on the input be calling preventDefault / stopPropagation, though? The input is, after all, handling the event.

andryyy commented 8 months ago

I don’t think HTMX knows even about that form.

It is a pretty strange markup. You are not really using that form but put all what makes a form a form into the button, even including its siblings' values (so to say).

It would make a bit sense if you removed the form altogether and included the values by their names or something. :) It would probably even work if you renamed the form to a div.

I’m not sure it’s a bug, it’s just not supposed to understand what’s going on.

reubenfirmin commented 8 months ago

Regardless of knowing the form, shouldn't it be calling preventDefault when it handles an event, though? (I think that if I did the same in js with preventDefault/stopPropagation that the form default wouldn't fire. Maybe incorrect.)

Yeah, the reason the markup is weird is that I'm using components (which I'm in the process of building) which have htmx actions attached to them. The form isn't modeled as part of the component, it's just a set of additional context that I need to send to the api. And vice versa, the components don't really know if they're inside a form or not, which is usually desirable, but in this case not.

Pulling the trigger up to the form did resolve this more cleanly though.

(PS the hx-include was leftover from an earlier approach and not needed, of course).

Telroshan commented 8 months ago

I think that if I did the same in js with preventDefault/stopPropagation that the form default wouldn't fire. Maybe incorrect

You are correct, see this JSFiddle, where indeed calling preventDefault prevents the submit.

If you look at htmx's code, only submit and click events are default-prevented, so in the case of a keypress event here, htmx doesn't prevent the event from bubbling up to the form and submitting. As andryyy said, since it's a convoluted situation, this wouldn't sound like a good example to me to have htmx preventDefault on other events than submit/click, I could be wrong though, feel free to convince me!