htmx icon indicating copy to clipboard operation
htmx copied to clipboard

hx-include including all matching elements in the page, not only from children

Open atelierJVA opened this issue 2 years ago • 3 comments

Not sure if this is a bug or if I am reading the doc wrong.

Inside a div, .filter-container in the example below, I have multiple inputs that I want to include in a request, so I added hx-include="[input]" to it, but for some reason the input in the outside div is also being included.

<div>
  <label for="outside_input">This input is not supposed to be included</label>
  <input id="outside_input" name="not_this_one" type="text">
</div>
<div class="filter-container" hx-include="input">
  <div class="filter-name">
    Include these:
  </div>
  <div class="filter-range">
    <label for="from">From</label>
    <input name="from" type="text">
    <label for="to">To</label>
    <input name="to" type="text">
  </div>
  <div class="buttons-group">
    <button hx-get="/path">Apply</button>
  </div>
</div>

When I fill the inputs and click in the Apply button I get path/?not_this_one=99&from=1&to=12, the query parameter not_this_one=99 is the one that should not be there.

From on the doc for hx-include : "Notes: hx-include is inherited and can be placed on a parent element" and the one for inheritance: "Most attributes in htmx are inherited: they apply to the element they are on as well as any children elements. "

So my assumption is that anything outside the element with hx-include should not be selected, is this wrong or is it a bug?

atelierJVA avatar Jun 22 '23 10:06 atelierJVA

Hey, the query selector passed to hx-include simply resolves to document.querySelectorAll. A standard CSS selector will not take the element defining the hx-include's position in the hierarchy

Take a look at hx-include documentation, where the example code is

<div>
    <button hx-post="/register" hx-include="[name='email']">
        Register!
    </button>
    Enter email: <input name="email" type="email"/>
</div>

You can see here, how the included input is not a child of the button, yet is included thanks to the [name='email'] selector.

So what can you do here? You may use the htmx extended selectors, so with your example code, you could do:

  1. <button hx-get="/path" hx-include="closest .filter-container">Apply</button> which will include the closest parent element that has the filter-container class, and thus, will include any input that is a child of that container This will not include the outside input, as it's not a child of that container Remember that, as the doc says:

    Note that if you include a non-input element, all input elements enclosed in that element will be included

  2. You may also add the container's class to the selector, to only include inputs that are children of it, not necessarily using the extended selector syntax, such as hx-include=".filter-container input", which will also ignore any input that is not a child of the container

  3. Just to expand on available options here, you might as well exclude the input you don't want, using the CSS :not pseudo-class, such as hx-include="input:not(#outside_input)"

  4. Also note that, even though I suppose this is just an example here, the doc also mentions

    This is a little contrived as you would typically enclose both of these elements in a form and submit the value automatically, but it demonstrates the concept.

    In your case, a form would indeed be a much clearer (and standard) option imo, such as

<form class="filter-container" hx-get="/path">
  <div class="filter-name">
    Include these:
  </div>
  <div class="filter-range">
    <label for="from">From</label>
    <input name="from" type="text">
    <label for="to">To</label>
    <input name="to" type="text">
  </div>
  <div class="buttons-group">
    <button type="submit">Apply</button>
  </div>
</form>

Here, you don't even need hx-include since the form handles that by default. You define the hx-get on the form, and use a submit button

Again, I suppose it's just an example you provided here, just thought it was worth mentioning

Telroshan avatar Jun 22 '23 19:06 Telroshan

Hi @Telroshan, thanks for the detailed answer, that makes sense based on the implementation.

Would it make sense to clarify this in the documentation?, the way I read it seems to imply that it uses the concepts described in the "Inheritance" section.

atelierJVA avatar Jun 22 '23 21:06 atelierJVA

You're right, inheritance is often confusing across attributes & behaviours ! I'll submit a PR sometime soon to improve the doc here (and also provide more code examples for hx-include I think)

Telroshan avatar Jun 22 '23 21:06 Telroshan