Possible to dynamically enable/disable `phx-update="ignore"`?

I’ve got this div – let’s call it dragging – in a Liveview . It has a Hook that runs sortableJS on the client to make the list drag-drop. For sortableJS to work properly, I need to have phx-update="ignore". However, on the same Liveview there are other forms that modify the content of the dragging div. But that whole div doesn’t update because it’s set to phx-update="ignore" . Is there a way to override this? Is there a way to make ignore dynamic?

ignore on

sortable works, updates don’t work

ignore off

sortable doesn’t work, updates work

Citation needed. I don’t have it on mine and I’m not seeing it on Chris’ todo_trek.

There semi-related discussion recently here. You definitely don’t need phx-update="ignore" for sortablejs to work, you likely just need to expand the scope of your hook.

2 Likes

Thanks for taking a stab at this

I think the reason I have phx-update="ignore" is because I’ve got multidrag on. Thanks for pointing me to todo_trek. I’ll go study and see how I can integrate those ideas.

1 Like

So, I took his project, added multidrag and it has a weird behavior with sortableJS. My beginner’s hunch is that multidrag and streams are conflicting.

You can see in the video that it selects the items properly, moves them, but its gets screwy when I drop them.

My guess is that sortable keeps track of selected items by referencing the HTML element and – when Phoenix streams updates – it recreates some HTML elements and sortable loses track of what was selected.

I RTFM’ed a bit further and found the solution of one part of the puzzle: onBeforeElUpdate.

let liveSocket = new LiveSocket("/live", Socket, {
  params: { _csrf_token: csrfToken },
  hooks: Hooks,
  dom: {
    onBeforeElUpdated(from, to) {
      const relevantAttributes = Array.from(from.attributes).filter(attr =>
        attr.name.startsWith("data-payload")
      );
      relevantAttributes.forEach(attr => {
        to.setAttribute(attr.name, attr.value);
      });
    
      const classesToTransfer = ["sortable-selected", "selected-item"];
    
      classesToTransfer.forEach(className => {
        if (from.classList.contains(className)) {
          to.classList.add(className);
        }
      });
    
    },
  },
});

So, now, when the DOM updates, it copies the classes over to the new divs that had it previously.

The only thing I still have to figure out is why when I click away from the sortable, it removes the sortable-selected class.

Hi, I remember an article by Fly.io about LiveView and Sortable.js. Possibly it will be helpful for you.

1 Like