LadyL
LadyL

Reputation: 23

Vue Draggable with touch - drop doesn't trigger

I have been working on a website that has to function on both desktop and tablets. Part of the website is having three columns and being able to drag orders from column to column. Sometimes on drop, the user has to answer a few questions or change some of the data of that specific order. This happens in a pop-up window that is triggered by an @drop function (for example @drop="approved()". The method approved() then checks the status of the dropped order and shows the pop-up window).

When I am on desktop, everything works just fine. But when I switch to iPad Pro in the developer tools, nothing happens. I implemented Vue Draggable, which says to work with touch devices. In their examples I can't find anything about touch events or adding new handles for touch, so I don't know what to do now. The dragging works just fine with touch devices, it's just the @drop function that doesn't trigger.

The dropzone (it includes a component that contains the draggables and a lot of if-statements):

<div class="col-md-4 border" @dragover.prevent @drop="approved()">
  <Wachtrij class="fullHeight" :data2="opdrachtenData2"></Wachtrij>
</div>

The method:

export default {
 methods: {
  ...
  approved() {
   console.log("Function approved() is being executed.")
   if (this.draggingOrder.status === 5) {
    this.popupGekeurd = true;
   }
   else if (this.draggingOrder.status === 6) {
    this.popupTochGoed = true;
   }
   else if ([40, 52, 42,41,49,55,54].indexOf(this.draggingOrder.status) !== -1) {
    this.back = true;
   }
  },
  ...
 }
}

Upvotes: 2

Views: 7239

Answers (1)

Sumurai8
Sumurai8

Reputation: 20737

The problem seems to be that you are using native events, while the touch implementation does not (always?) use these events. It is intended that you use a draggable component with one of the events outlined in the documentation. In your case the start and end events look promising. This event has a few properties (docs), some of them being to and from.

Let's assume that we have the following code:

<draggable v-for="(zone, index) in zones" v-model="zones[index]" :class="['dropzone', `zone-${index}`]" :key="`dropzone-${index}`" :options="options" @start="start" @end="end">
  <div v-for="item in zones[index]" class="dropitem" :key="`dropitem-${item.id}`">
    {{ item.title }}
  </div>
</draggable>

This creates a few zones, each filled with their own items. Each array item of zones is changed based on where you move each item. You can then use start to have information on when you start moving an item, and end to have information on when you stop moving an item, and where that item came from and where it ended up. The following methods show off what you can do with that in this case:

  methods: {
    start (event) {
      console.log('start', event);
    },

    end (event) {
      console.log('end', event);

      const { from, to } = event;
      if (to.className.match(/\bzone-2\b/)) {
        console.log('Zone 2 has something added!')
      }
      if (from.className.match(/\bzone-0\b/)) {
        console.log('Zone 0 had something removed!');
      }
    }
  }

We make our dropzones with a class zone-0, zone-1 or zone-2 in this case, so we can use the class name to determine which dropzone we ended up in.


An alternative way to determine which zone was changed is to simply use a watcher. Since zones changes based on where you move items, you can simply watch a particular dropzone for changes and do things based on that.

  watch: {
    'zones.1': {
      handler (oldZone, newZone) {
        if (Array.isArray(oldZone) && Array.isArray(newZone) && oldZone.length !== newZone.length) {
          console.log('Zone 1 was changed from', oldZone, 'to', newZone);
        }
      }
    }
  }

A full example can be found on codesandbox.

Edit Vue Template

Upvotes: 2

Related Questions