I got it to work with some extra help from AlpineJS.
The complexity of this solution is because Chrome-based browsers don't trigger HTMX when the <select>
's value changes.
This solution uses Alpine to:
- react to the event (with the
@change
attribute)
- find the
option
element corresponding to the value (using document.evaluate
and an xPath selector to look for children of the select
element, $el
.)
- then trigger HTMX on that element.
<select
name="make"
hx-target="#models"
x-data="{
renderXPathSelector(value) {return `.//option[contains(., '${value}')]`},
getChosenOption(value) {return document.evaluate(this.renderXPathSelector(value), $el).iterateNext()},
tellHTMXOptionChanged(event) { htmx.trigger(this.getChosenOption(event.target.value), 'click')}
}"
@change="tellHTMXOptionChanged($event)"
>
<option hx-get="/models/audi">Audi</option>
<option hx-get="/models/toyota">Toyota</option>
<option hx-get="/models/bmw">BMW</option>
</select>
If you have select
s whose values are different than the text, you can use select the option
in a more simple way:
el.querySelector(`[value="${el.value}"]`)
You can support both cases by setting the chosenOption
function to:
const chosenOption = el.querySelector(`[value="${el.value}"]`) ||
getChosenOption(event.target.value)
If you want to use this pattern several times across your app, you can create an "Alpine magic" to simplify the HTML:
<script>
document.addEventListener('alpine:init', () => {
Alpine.magic('tellHTMXOptionChanged', (el) => {
{# This is needed for cross-browser compatability for when a <select> changes #}
return (event) => {
function renderXPathSelector(value) {return `.//option[contains(., '${value}')]`}
function getChosenOption(value) {return document.evaluate(renderXPathSelector(value), el).iterateNext()}
const chosenOption = el.querySelector(`[value="${el.value}"]`) || getChosenOption(event.target.value)
htmx.trigger(chosenOption, 'click')
}
})
})
</script>
...
<select
name="make"
hx-target="#models"
x-data
@change="$tellHTMXOptionChanged($event)"
>
<option hx-get="/models/audi">Audi</option>
<option hx-get="/models/toyota">Toyota</option>
<option hx-get="/models/bmw">BMW</option>
</select>