SortableJS / vue.draggable.next

Vue 3 compatible drag-and-drop component based on Sortable.js
https://sortablejs.github.io/vue.draggable.next/#/simple
MIT License
3.91k stars 531 forks source link

Detecting drop of items onto dropzone before destination list is updated. #227

Closed colinbes closed 1 year ago

colinbes commented 1 year ago

I am confused as to the status of multidrag/drop support in vuedraggable-next. I see mention made of adding it to library but nothing more.

In my case I don't need to do a multi select as my select object contains a list of elements and all I need to do is intercept this drop on my target and bypass merging of list and do it myself but I don't know what event to listen to - it appears that @change event is too late as items are already added.

As example:

 Drop zone has: [{name: 'Bob', age: 30}, {name: 'Ann', age: 32}, {name: 'Ari', age: 20}]
and I drop  [{name: 'Curt', age: 40}, {name: 'Mary', age: 33}]  over second position I end up with
[{name: 'Bob', age: 30}, [{name: 'Curt', age: 40}, {name: 'Mary', age: 33}],{name: 'Ann', age: 32}, {name: 'Ari', age: 20}]

I can clear this up by splicing but @change event is too late as the rendering has already started and I get errors of element.name and element.age not being valid for 2nd item in updated list which is correct as it's an array. If I could somehow tap into event before the destination list is updated I can work around this.

colinbes commented 1 year ago

What I have done for now is to use the v-model for specifying the list as it doesn't auto update list on changes as :list does.

Working code snippet:

<draggable class="dragArea"
                     v-model="theList"
...
>

And

const list2 = ref<StageModuleNG[]>([])

onMounted(async () => {
  const recipes = getRecipes()
  list2.value = recipes[0].program //mock
})

const theList = computed({
  get: () => list2.value,
  set: (list: StageModuleNG[]) => {

    let newList: StageModuleNG[] = []
    list.forEach((value: any, _index: number) => {
      if (Array.isArray(value)) {
        value.forEach(item => newList.push(item))
      } else {
        newList.push(value)
      }
    })

    list2.value = newList
  }
})

I am sure this can be further optimized but for now is a working proof of concept