htmx icon indicating copy to clipboard operation
htmx copied to clipboard

Morphdom extension not working with changes through the Websocket extension

Open advdv opened this issue 3 years ago • 6 comments

I'm experimenting with a setup where updates to my UI are received through a websocket connection. These updates may contain arbitrarily complex html so I wanted to make sure to cover may bases and use morphdom for the swapping mechanism. My HTML looks like this:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <script src="https://unpkg.com/[email protected]"></script>
    <script src="https://unpkg.com/[email protected]/dist/ext/ws.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/morphdom-umd.min.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/ext/morphdom-swap.js"></script>
    <script>
   // _NOTE: I copied the morhdom extension into my own script tag so I could debug it. But the behaviour is the same If I 
   // include it through a CDN.

    console.log("loading");
    htmx.defineExtension('morphdom-swap', {
        isInlineSwap: function(swapStyle) {
            console.log("isInlineSwap", morphdom, swapStyle);
            return swapStyle === 'morphdom';
        },
        handleSwap: function (swapStyle, target, fragment) {
            console.log("handleSwap", morphdom)
            if (swapStyle === 'morphdom') {
                if (fragment.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
                    morphdom(target, fragment.firstElementChild);
                    return [target];
                } else {
                    morphdom(target, fragment.outerHTML);
                    return [target];
                }
            }
        }
    });    
    </script>
  </head>
  <body hx-ext="morphdom-swap" hx-swap="morphdom"> 
    <div hx-ext="ws" ws-connect="/logz/log-ws-trigger">
      <div id="log-container"></div>
    </div>  

    <button hx-get="/test">Click Me!</button>
  </body>
</html>

When I use the "Click me" button. the morphdom extension is correctly called and the swap is handled. But when changes are coming through the websocket connection morphdom is not used.

I've tried to place the hx-swap="morphdom" on all the different elements, and did the same with the hx-ext="morphdom-swap".

Is this use case not supported, or am I doing something wrong?

advdv avatar Mar 13 '22 09:03 advdv

Did you try placing them on the same element, comma separated? e.g. <div hx-ext="ws,morphdom-swap" ...? (I have a custom transformResponse handler that I use with ws - that's what works for me. I'm also sending UI updates through ws.)

KenWhitesell avatar Mar 13 '22 12:03 KenWhitesell

Thank you for response, but unfortunately that doesn't change anything. What function get's called by your transformResponse handler? It seems to me that websocket swaps never call the "handleSwap" of the morphdom extension. Does your transformResponse have a "handleSwap" that gets called?

advdv avatar Mar 14 '22 14:03 advdv

I don't make any htmx api calls in my transformResponse. It accepts a JSON response from the server, does some work with some of the data, and returns the html text to be added to the page by htmx.

Sorry, I've not done anything with the "handleSwap" event.

KenWhitesell avatar Mar 14 '22 22:03 KenWhitesell

the websocket infrastructure treats all swaps as out of band: https://github.com/bigskysoftware/htmx/blob/74f520cf8b818c64aa79009449e24f4ac8be1497/src/htmx.js#L1417

is htmx helping much here? Seems like you've got a pretty specific setup you want and a plain web socket working w/ morphdom might give you better control...

1cg avatar Apr 07 '22 20:04 1cg

can you try w/ the latest version in the dev branch?

@Renerick made some very nice changes to web sockets that integrates it much more tightly w/ the standard swap semantics.

1cg avatar May 27 '22 17:05 1cg

I think, you need to specify hx-swap-oob="morphdom" in the websocket message, not in the page body.

Renerick avatar May 27 '22 19:05 Renerick