Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hx-trigger~~'s consume modifier~~ has surprising behaviour with forms #2919

Open
robryk opened this issue Sep 19, 2024 · 3 comments
Open

hx-trigger~~'s consume modifier~~ has surprising behaviour with forms #2919

robryk opened this issue Sep 19, 2024 · 3 comments
Labels
bug Something isn't working

Comments

@robryk
Copy link

robryk commented Sep 19, 2024

E: see below for details, consume is completely orthogonal to the issue (it's rather about hx-trigger's presence alone affecting the two forms differently)

hx-trigger="click consume" seems to prevent the button from triggering its form when its enclosed in that form, but not when it references its form by id. In the following example, "click me 1" does nothing while "click me 2" causes an attempt at form submission:

<html>
<head>
<script src="https://unpkg.com/[email protected]" integrity="sha384-Y7hw+L/jvKeWIRRkqWYfPcvVxHzVzn5REgzbawhxAuQGwX1XWe70vji+VSeHOThJ" crossorigin="anonymous"></script>
</head>
<body>
<form action="http://foo" method="POST"><button hx-trigger="click consume">click me 1</button></form>
<form id="bar" action="http://bar" method="POST"></form><button form="bar" hx-trigger="click consume">click me 2</button>
</body>
</html>

The documentation doesn't explicitly say that such form submissions will be prevented (it only mentions other htmx requests; admittedly it calls out htmx requests on parents), but I'd expect that not to differ between these two setups, given that they're used interchangeably (and ttbomk do not differ in behaviour in HTML at all).

@MichaelWest22
Copy link
Contributor

Yeah It is interesting. documentation points out or on elements listening on parents and forms have a browser built in listener on button clicks.

in the first form you have there the button click event is consumed so it will not bubble up to the form and trigger the form submit as this is how buttons in forms trigger things. And because the button has no other hx-attributes htmx has no action to complete itself in this case so does nothing.

In the second situation you have used the form=id attribute on the button which the browser uses to retarget the submit trigger from the button click to the form located somewhere else on the page. So you would expect the htmx consume here would prevent the button click bubbling up to its parent form (but there is none) in this case and its probably working as expected. But the default browser behavior of redirecting events to a remote form will still be in place as htmx doesn't alter default browser functions by design.

@robryk
Copy link
Author

robryk commented Sep 20, 2024

If you read the documentation very literally, it only claims that hx-trigger's consume modifier affects other htmx requests, which should not include vanilla HTML form submission. So, regardless of what's the intended behaviour wrt forms here, the documentation doesn't describe the current behaviour accurately.

@Telroshan
Copy link
Collaborator

Yeah after all it all comes down to this about consume:

htmx/src/htmx.js

Lines 2439 to 2441 in 326ff3b

if (triggerSpec.consume) {
evt.stopPropagation()
}

The docs could probably be improved to specify that consume will simply call stopPropagation

Though, it should be noted here that it's not consume that prevents your form from submitting, as the event.stopPropagation doc mentions

The stopPropagation() method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases. It does not, however, prevent any default behaviors from occurring; for instance, clicks on links are still processed. If you want to stop those behaviors, see the preventDefault() method.

Using your example above, you can see on this JSFiddle that even without the consume keyword, the form is still prevented from submitting.

The preventDefault call comes from here:

htmx/src/htmx.js

Lines 2396 to 2398 in b71af75

if (explicitCancel || shouldCancel(evt, elt)) {
evt.preventDefault()
}

shouldCancel itself, will return true if the element is a submit button inside a form and the event is a click or a submit

htmx/src/htmx.js

Lines 2320 to 2322 in b71af75

if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) {
return true
}

The idea being that if a button has a hx-trigger attribute defined, it's normally going to make a request (you didn't put any hx-get/post/whatever in your example on the buttons themselves but I assume there would be one of those in a real situation), thus we want to prevent the enclosing form's default submit.
You can see the problematic behavior on this JSFiddle, almost the same example as before, I just added hx-post attributes to the button. See how the second one does 2 requests ; the htmx one + the default submission. We probably don't ever want that to happen.

So I would say this is a bug, we actually didn't have any support for the form attribute a year back (see #1559 #1815), it's very likely to have simply been overlooked (by none other than myself, sigh) at that time.
Maybe it coud simply be fixed by replacing the closest form check in shouldCancel by this one:

htmx/src/htmx.js

Line 2715 in b71af75

const form = resolveTarget('#' + getRawAttribute(elt, 'form'), elt.getRootNode()) || closest(elt, 'form')

So, to sum it up:

  • consume has actually nothing to do with the issue here, as it stops propagation but does not prevent default
  • the real issue is that the form attribute isn't processed at all right now to determine whether we should prevent default submission or not (and in this case, we should)

If you'd like to look into it, feel free to investigate and submit a bugfix PR! And add test cases of course 😁

@Telroshan Telroshan added the bug Something isn't working label Sep 21, 2024
@robryk robryk changed the title hx-trigger's consume modifier has surprising behaviour with forms hx-trigger~'s consume modifier~ has surprising behaviour with forms Sep 21, 2024
@robryk robryk changed the title hx-trigger~'s consume modifier~ has surprising behaviour with forms hx-trigger~~'s consume modifier~~ has surprising behaviour with forms Sep 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants