Search code examples
vue.jsvuedraggable

How can i add a confirmation Pop up modal with Vue Draggable?


I have an vue component which uses Vue Draggable .

<template>
  <div class="row my-5">
    <div v-for="column in columns" :key="column.title" class="col">
      <p class="font-weight-bold text-uppercase">{{column.title}}</p>
      <!-- Draggable component comes from vuedraggable. It provides drag & drop functionality -->
      <draggable :list="column.tasks" :animation="200" ghost-class="ghost-card" group="tasks" :move="checkMove">
        <transition-group>        
          <task-card
            v-for="(task) in column.tasks"
            :key="task.id"
            :task="task"
            class="mt-3 cursor-move"
          ></task-card>
          <!-- </transition-group> -->
        </transition-group>
      </draggable>
    </div>
  </div>
</template>


<script>
import draggable from "vuedraggable";
import TaskCard from "../board/TaskCard";
export default {
  name: "App",
  components: {
    TaskCard,
    draggable,
  },
 data() {
    return {
      columns: [
                 .....
             ],
    };
  },
  methods: {
   checkMove: function(evt){   
    console.log('moved');
}
  },
};
</script>

In TaskCard Component -

<template>
  <div class="bg-white shadow rounded p-3 border border-white">
    <div class="d-flex justify-content-between align-items-center mb-3">
      <h2>{{task.id}}</h2>
      <span>{{task.date}}</span>
    </div>
    <p class="font-weight-bold">{{task.title}}</p>
  </div>
</template>
<script>
export default {
  props: {
    task: {
      type: Object,
      default: () => ({}),
    },
  },
};
</script>


When I move an item, I want a modal that confirms the change and only then move the item. (ie. if I click on the cancel button inside the modal, the item should not be moved.)

How can this be achieved using the checkMove() function provided?


Solution

  • I don't think you can achieve this by using onMove event. The onEnd event it seems more suitable but unfortunately it doesn't have any cancel drop functionality.

    So I think the only solution here is revert it back if the user decides to cancel.

    You can listen on change event (See more in documentation)

    <draggable
      group="tasks"
      v-model="column.tasks"
      @change="handleChange($event, column.tasks)">
      ...
    </draggable>
    ...
    <button @click="revertChanges">Cancel</button>
    <button @click="clearChanges">Yes</button>
    

    And

    ...
      handleChange(event, list) {
        this.changes.push({ event, list })
        this.modal = true
      },
    
      clearChanges() {
        this.changes = []
        this.modal = false
      },
    
      revertChanges() {
        this.changes.forEach(({ event, list }) => {
          if (event.added) {
            let { newIndex } = event.added
            list.splice(newIndex, 1)
          }
    
          if (event.removed) {
            let { oldIndex, element } = event.removed
            list.splice(oldIndex, 0, element)
          }
    
          if (event.moved) {
            let { newIndex, oldIndex, element } = event.moved
            list[newIndex] = list[oldIndex]
            list[oldIndex] = element
          }
        })
    
        this.changes = []
        this.modal = false
      }
    ...
    

    JSFiddle example