Open ouvreboite opened 1 month ago
Yeah the way form="xxx" and also hx-include work for adding remote inputs into a forms response do not propagate all of the various events from the remote objects back to the form. events like changed only bubble up to parents and this is just how events work in browsers sorry. Their are some exceptions like for buttons with form= set i think as these fire submit events to the remote form but this is all browser logic and not htmx.
I think the best solution is adding simple JS to the remote input to trigger the form which is what you have done. It is possible just with htmx to move the hx-get on the form up to a higher parent object to capture both the form and the selects change event and fire the request properly like this:
<body hx-get="item.html"
hx-trigger="change"
hx-target="#results"
hx-swap="afterend"
hx-include="#myForm">
<section>
<h1>Form</h1>
<small>Selecting a value will trigger HTMX</small>
<form
id="myForm"
"
>
<label>
selectInForm
<select name="selectInForm">
<option>a</option>
<option>b</option>
<option>c</option>
</select>
</label>
</form>
</section>
<section>
<h1>Outside the form</h1>
<small>HTMX is unable to react to change</small>
<label>
selectOutForm
<select name="selectOutForm" form="myForm">
<option>1</option>
<option>2</option>
<option>3</option>
</select>
</label>
</section>
</body>
This is not ideal on the body in this example but it shows how the events bubble up to parents and how you can use this sometimes.
You can also extend the attributes on the select to make it fire whatever event you like with htmx like this:
<select name="selectOutForm" form="myForm"
hx-get="item.html"
hx-trigger="change"
hx-target="#results"
hx-swap="afterend"
hx-include="#myForm">
<option>1</option>
<option>2</option>
<option>3</option>
</select>
and then this select will function as its own customized htmx activated element. Also the hx-target, hx-swap and hx-include can all use inheritance so could be placed on a mutual parent element to reduce the attribute duplication if possible.
Note that you can also use the from
modifier of hx-trigger
For example, defining
<form id="myForm" hx-post="/whatever" hx-trigger="change, change from:[form='myForm']">
<input ...>
...
</form>
<input form="myForm" ...>
will catch the change
event on the form itself (thus on any contained child), but also from any input that defines the attribute form="myForm"
Note that, as the doc mentions about from
:
The CSS selector is only evaluated once and is not re-evaluated when the page changes. If you need to detect dynamically added elements use an event filter, for example click[event.target.matches('input')]
If you need a form that handles dynamically added external inputs, you could listen on the body instead and filter the triggering elements, something like
<form id="myForm" hx-post="/whatever" hx-trigger="change, change[event.target.matches('[form=\'myForm\']')] from:body">
<input ...>
...
</form>
<input form="myForm" ...>
You can try it out on this JSFiddle
In HTML, it's possible to have form components (buttons, inputs, selects, ...) outside of a form by adding the
form=#myFormId
attribute on them.Using HTMX (via hx-boost or hx-get/hx-post) the outside select value is used correctly when making the call ✅ (ex:
/currentPage?text=abc&outside=a
)But I can't find a way to trigger the form when the outside select value change.
Example of the behavior: https://plnkr.co/edit/sXNvKYobVl6iD5NQ
A stopgap solution is to add a bit of JS on each out-of-form input:
onchange="this.form.requestSubmit()"
and havehx-trigger="submit change"