sortablejs-vue3 icon indicating copy to clipboard operation
sortablejs-vue3 copied to clipboard

Button @click event is lost on Clone

Open marcopixel opened this issue 1 year ago • 1 comments

Description

When attempting to move/clone a element from the left list to the right one the click event is lost because the original click event is on the "clone" inside the right list. The expected behavior is that all elements should retain all events on the elements inside.

Environment:

[email protected] /home/projects/vitejs-vite-9v4mkx
+-- @vitejs/[email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
`-- [email protected]

Browser: Chrome 123.0.6312.106

Repro Case

https://stackblitz.com/edit/vitejs-vite-ilyqms?file=src%2FApp.vue

Steps to Reproduce:

  1. Grab an element from the left box
  2. Try to drop it on the right box
  3. The box will be cloned correctly but the click event in the left box is lost (you can check it by clicking the button and see the number increase with every click)

Expected: The element should be cloned to the right box and all buttons should increase the Trigger Count by +1. Actual: The element is moving normally but the original element in the left element has lost the @click event from the button

https://github.com/MaxLeiter/sortablejs-vue3/assets/3743025/9a6aa0ea-e4cd-4293-9b14-1650c0f7ef9a

marcopixel avatar Apr 08 '24 12:04 marcopixel

The problem here is that the newly cloned or moved card isn't a vue component but a rendered version of it.

I think you can solve your issue by having a state where you manage your lists (not neccessarily pinia, vuex or anything like that). When you drag the card into a new column you add it to that list. It will then look like you add 2 items every time you add an item - one is probably working as you'd expect and one is not. To solve this you can remove the node thats not a vue component. I got this technique from this https://github.com/MaxLeiter/sortablejs-vue3/issues/23#issuecomment-1238111107 thread.

Here is more or less how I solved it:

 <Sortable
      :list="list"
      item-key="id"
      :options="options"
      :data-kanban-stage-id="stage.id"
      tag="ul"
+     @add="onAdd($event)"
+     @remove="onRemove($event)"
    >

function removeNode(node: HTMLElement) {
  if (node.parentElement !== null) {
    node.parentElement.removeChild(node);
  }
}
async function onAdd(event: SortableEvent) {
  nextTick(async () => {
    const nodeItem = event.item
    const cardId = Number(nodeItem.dataset.id) // I chose to add ID to the data attribute, there is probably other ways of doing this
    const newListNodeId = Number(event.to.dataset.kanbanStageId)
    
   // optional: Update backend
   // Update local list  

    removeNode(nodeItem) // remove visual representation
  });
}

function onRemove(event: SortableEvent) {
  
  nextTick(() => {
    const cardId = Number(event.item.dataset.id)
   // optional: Update backend
   // update the local list you want it to be removed from 
  });
}

Note: My columns are in their own SFC so no need to get the parent element in the event but it would be in your case.

RHellenes avatar May 07 '24 09:05 RHellenes