Weird behaviour when swapping innerHTML vs outerHTML
Hello, I have this weird case. I use HTMX together with TomSelect.
I init my selects after swapping like so:
document.body.addEventListener('htmx:afterSettle', async (event) => {
event.detail.target.querySelectorAll("[is-tomselect]").forEach((elem) => {
new TomSelect(elem, {...});
});
});
The returned html looked like so:
<div id="container">
{% partial %}
<div id="div_that_gets_sent_in_response" <---- only this div and it's contents get sent in the response
hx-get="<some_url>"
hx-trigger="refresh from:body"
hx-swap="outerHTML"
hx-target="this"
<select is-tomselect>...</select>
....
</div>
{% endpartial %}
</div>
First swap eveything worked well, but if I did the swap a second time I would get this error:
Error: Tom Select already initialized on this element
Which is weird because the select was supposed to be replaced with a new fresh one.
The error is thrown by tomselect with this line of code of the constructor:
if (input.tomselect) { throw new Error('Tom Select already initialized on this element'); }
It checks to see if the elements has already been initialized. But all of this takes place after the dom has settled so all elements should be "fresh".
After a lot of debugging I found out that if I change the returned html to one below everything worked no matter how many swaps I did:
<div id="container">
{% partial %}
<div id="div_that_gets_sent_in_response" <---- only this div and it's contents get sent in the response
hx-get="<some_url>"
hx-trigger="refresh from:body"
hx-swap="innerHTML" <--- this changed
hx-target="#container" <--- this changed
<select is-select>...</select>
....
</div>
{% endpartial %}
</div>
Somehow changing the swap method to innerHTML instead outerHTML deletes the old tomselect instances and everything works. But using outerHTML keeps the instances alive.