vuejs3vue-composition-apivuedraggableprimevue

How to drag rows from one DataTable to another? (PrimeVue)


I'm trying to drag rows from one DataTable to another. This animation shows what I try to achieve, kind off.

But from the looks of it PrimeVue doesn't seem to support this, or at least I can't figure out why.

Plan B is to use vue.draggable but seeing as I cannot isolate a child row-item from the datatable, I don't think I can wrap it in a draggable component.

The code used in the animation:

<template>
  <div class="flex justify-content-center gap-4">
    <DataTable :value="cars1" @row-reorder="onRowReorder">
      <Column :rowReorder="true" headerStyle="width: 3em" />
      <Column field="brand" header="brand"></Column>
      <Column field="color" header="Color"></Column>
    </DataTable>

    <DataTable :value="cars2" @row-reorder="onRowReorder">
      <Column :rowReorder="true" headerStyle="width: 3em" />
      <Column field="brand" header="brand"></Column>
      <Column field="color" header="Color"></Column>
    </DataTable>
  </div>
</template>

<script setup>
const cars1 = ref([
  { brand: "BMW", color: "Green" },
  { brand: "Volvo", color: "Yellow" },
  { brand: "Audi", color: "Red" },
  { brand: "Ford", color: "Pink" }
]);
const cars2 = ref([]);

function onRowReorder(event) {
  const draggedCar = cars1.value[event.dragIndex]
  cars2.value.push(draggedCar);
}
</script>

Solution

  • You can build it yourself by using @vueuse's useDropZone utility function and by using the template in the column of the reorder icon.

    That way you stil use PrimeVue's dragging logic, but you can intercept it yourself with mousedown and mouseup events in combination with the onDrop callback of the useDropZone utility function. See snippet below.

    <template>
      <div class="flex">
        <DataTable :value="cars1">
          <Column :rowReorder="true" headerStyle="width: 3em">
            <template #body="{ index, data }">
              <i
                @mousedown="onHandleClick(index, data)"
                @mouseup="clearHandle"
                :class="['p-datatable-reorderablerow-handle', 'pi pi-bars']"
              ></i>
            </template>
          </Column>
          <Column field="brand" header="brand"></Column>
          <Column field="color" header="Color"></Column>
        </DataTable>
    
        <DataTable ref="dropzoneTable" :value="cars2">
          <Column :rowReorder="true" headerStyle="width: 3em" />
          <Column field="brand" header="brand"></Column>
          <Column field="color" header="Color"></Column>
        </DataTable>
      </div>
    </template>
    
    <script setup>
    const cars1 = ref([
      { brand: 'BMW', color: 'Green' },
      { brand: 'Volvo', color: 'Yellow' },
      { brand: 'Audi', color: 'Red' },
      { brand: 'Ford', color: 'Pink' },
    ]);
    const cars2 = ref([]);
    
    const dropzoneTable = ref();
    const { isOverDropzone } = useDropZone(dropzoneTable, onDrop);
    
    const draggingRow = ref();
    
    function onHandleClick(index, data) {
      draggingRow.value = data;
    }
    
    function onDrop() {
      cars2.value.push(draggingRow.value);
    }
    
    function clearHandle() {
      draggingRow.value = null;
    }
    </script>
    

    https://stackblitz.com/edit/nuxt-starter-pp7mdb?file=app.vue