22

I have several draggable elements

<div Class="question-item" draggable="true">Box 1: Milk was a bad choice.</div>
<div class="question-item" draggable="true">Box 2: I'm Ron Burgundy?</div>
<div class="question-item" draggable="true">Box 3: You ate the entire wheel of cheese?     </div>
<div class="question-item" draggable="true">Box 4: Scotch scotch scotch</div>

And I have the following event handlers:

var $questionItems = $('.question-item');

$questionItems
  .on('dragstart', startDrag)
  .on('dragend', removeDropSpaces)
  .on('dragenter', toggleDropStyles)
  .on('dragleave', toggleDropStyles);


function startDrag(e){
  console.log('dragging...');
  addDropSpaces();
  e.stopPropagation();
}

function toggleDropStyles(){
  $(this).toggleClass('drag-over');
  console.log(this);
}


function addDropSpaces(){
  $questionItems.after('<div class="empty-drop-target"></div>');
}

function removeDropSpaces(){
  console.log("dragend");
  $('.empty-drop-target').remove()
}

Why does it only work for the first draggable. If I drag say the last draggable - the dragend event is fired immediately. (I don't want to use jQuery UI btw)

It makes no sense to me - it looks like a bug.

I am on Chrome v 30 on OSX.

Here is a link to the JSFiddle: http://jsfiddle.net/joergd/zGSpP/17/

(Edit: this is repeat of the following question: dragend, dragenter, and dragleave firing off immediately when I drag - but I think the original poster was fine to go with jQuery UI, whereas I want it to be HTML5 native)

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Joerg
  • 3,553
  • 4
  • 32
  • 41

4 Answers4

22

As i mentioned in the topic dragend, dragenter, and dragleave firing off immediately when I drag , what solved the problem (which looks to be a Chrome bug) for me was to add a setTimeout of 10 milliseconds into the handler and manipulate the DOM in that timeout.

Community
  • 1
  • 1
Ivan Koshelev
  • 3,830
  • 2
  • 30
  • 50
  • Just to possibly narrow down the problem, I observed in my case (React, Redux action that causes subtree collapsing) that this issue happens only in case the scrollbar hits the bottom after that DOM modification, which causes drag position to jump to a different position relative to the container. I assume that the browser engine considers that as an inconsistency and cancels the drag operation, which would explain the behavior and the workaround. Modifying the DOM the same way but later is a normal mouse move. I assume the same would happen if the modification was done above the dragged item. – martinh_kentico Mar 15 '21 at 16:43
  • I've found that setting the timeout to 0 even works. – W Biggs Jun 10 '21 at 23:38
14

I don't have a direct solution, but changing the DOM in the dragStart event handler is causing this problem, and any code that changes the DOM should really go in the dragEnter event handler - doing so, drag&drop events are fired more reliably.

Not sure whether this is by design - it feels a bit like a bug though.

Joerg
  • 3,553
  • 4
  • 32
  • 41
9

This is a known chrome issue. Problem is, as Joerg mentions that you manipulates the dom on dragstart.

You can do so, but you need to do it in a timeout.

user1351905
  • 142
  • 1
  • 6
1

Just had the same problem. I was manipulating the DOM by changing an elements position to fixed in dragStart. I fixed my issues using Ivan's answer like this:

/* This function produced the issue */
function dragStart(ev) {
    /* some code */
    myElement.style.position="fixed";
}

/* This function corrected issue */
function dragStart(ev) {
    /*some code */
    setTimeout(function changePos() {
        myElement.style.position="fixed";
        }, 10);
}

It seems like the answer to your problem would be

function startDrag(e){
  console.log('dragging...');
  setTimeout(addDropSpaces(),10);
  e.stopPropagation();
}