htmx icon indicating copy to clipboard operation
htmx copied to clipboard

htmx ignores hx-* options if calling element is removed

Open danjac opened this issue 4 years ago • 1 comments

Use case: there is a link in a modal. Links in the modal have the following top-level settings:

<div id="modal"
        hx-boost="true"
        hx-select="#content"
        hx-target="#content>
<div class="modal-body">
   <a href="some-url">...</a>

When a link in the modal is clicked, some JS automatically removes the modal from the DOM, in effect closing the modal.

What appears to happen is that the hx-boost action works, but the hx-select option is ignored. If instead I just hide the modal (i.e. display:none) then hx-select works.

I think what happens is that htmx does the fetch, and then checks the calling element for the options on how to render the content. If the element is missing, it falls back to whatever defaults. What should probably happen is that the options are parsed before the fetch, so it doesn't matter if the calling element (<a> in this case or its parent) is still in the DOM.

danjac avatar May 21 '21 09:05 danjac

I think this may be a misunderstanding, but maybe I'm wrong? I could not reproduce the behavior you described...but I did produce maybe something similar, but it wasn't unexpected necessarily.

In this example, obviously the second link works no problem clicking the first link removes the modal immediately and also causes the behavior you mentioned (i.e. the hx-target is "ignored")

<div class="container">
    <div id="content">
        We want to render in here
    </div>
    <div class="my-modal" hx-boost="true" hx-target="#content">
      <a href="/contacts" onClick="document.querySelector('.my-p').remove()">Removes Modal</a>
      <a href="/contacts">Does not remove modal</a>
   </div>
</div>

However, it should be noted that this does not just ignore the "target", this causes a full page refresh like clicking a regular link. Meaning that the request is not being made by htmx, but rather the regular browser behavior. The order of a events is:

  1. link clicked
  2. My attached JS immediately removes the modal
  3. htmx event with boost is never triggered

However, we can easily modify the above example to get the desired behavior

Assuming HTMX script is included in the head already

<div class="container">
    <div id="content">
        We want to render in here
    </div>
    <div class="my-modal" hx-boost="true" hx-target="#content">
      <a href="/contacts" id="my-button">Removes Modal</a>
      <a href="/contacts">Does not remove modal</a>
   </div>
</div>
<script>
   const myBtn = document.querySelector('#my-button');
   myBtn.addEventListener('click', () => {
     document.querySelector('.my-modal').remove()
   });
</script>

In this case, since the HTMX event is the first event handler to be run:

  1. the ajax request is launched,
  2. #my-modal is removed
  3. the requested HTML is rendered in #content

aburd avatar Feb 22 '24 15:02 aburd