I'm showing a loading spinner on my page when triggering a htmx-request like so:
<div class="col-4 px-4dot5 py-3 bg-secondary-light">
<label for="stellenangebotLink" class="form-label fs-5">Link</label>
<div id="linkHelpBlock">E-Mail-Adresse oder Website-URL</div>
<?= $this->include('components/_htmx_spinner') ?>
<input
hx-post="/medien/personal-kampagne/stellenangebot-modal/link"
hx-trigger="keyup changed delay:300ms"
hx-include="#stellenangebot_id"
hx-target="#stellenangebotLinkWrapper"
hx-indicator=".htmx-indicator"
name="link"
id="stellenangebotLink"
class="form-control"
aria-describedby="linkHelpBlock">
</div>
Spinner code:
<div id="spinner" class="spinner-border spinner-border-sm mx-2 htmx-indicator" role="status">
<span class="visually-hidden">Loading...</span>
</div>
The problem is that i have multiple such elements on my page and i only want to show the closest spinner. Furthermore i want to reuse that spinner-fragment on other elements (no sequential Ids).
The hx-indicator page says:
The value of this attribute is a CSS query selector of the element or elements to apply the class to, or the keyword closest, followed by a CSS selector, which will find the closest ancestor element or itself, that matches the given CSS selector (e.g. closest tr);
But what is such a CSS selector? closest .htmx-indicator
gives a javascript-error (htmx.min.js:1 Uncaught TypeError: Cannot read properties of null (reading 'htmx-internal-data')
). closest div
would be too broad.
So my question is: How can i select the closest spinner-fragment with hx-indicator
?
It looks like they "translate" closest .htmx-indicator
into the method call .closest('.htmx-indicator')
- but that alone won't help you here, to actually target the .htmx-indicator
element. .closest()
checks the element itself and all its ancestors for a match to the selector - but your .htmx-indicator
is not an ancestor of the input element, so it won't be found (and that then in turn explains the JS error you got.)
You would need to traverse downwards in the DOM tree again to actually find that spinner element, after you found a common ancestor of both, something like .closest('div').querySelector('.htmx-indicator')
- but it doesn't look they provide any "syntax" for that.
closest div
would be too broad
Why? According to their documentation, whatever element you actually target, will get the htmx-request
class added to it; and the stylesheet should already come with
.htmx-request .htmx-indicator{
opacity:1
}
.htmx-request.htmx-indicator{
opacity:1
}
So whether you manage to get the .htmx-indicator
element itself getting the class htmx-request
applied to it, or whether it gets set on the outermost div
in your given example code, should not really matter - it should apply the opacity value to .htmx-indicator
either way ...?
(And that ID there on <div id="spinner"
should go, if you include that same code in multiple places on one page.)