htmx icon indicating copy to clipboard operation
htmx copied to clipboard

Weird behaviour when swapping innerHTML vs outerHTML

Open paulik123 opened this issue 1 year ago • 0 comments

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.

paulik123 avatar Apr 21 '24 19:04 paulik123