Skip to main content

Search and Top Navigation

#6259 open bug ()

Opened November 03, 2010 04:11PM UTC

Last modified March 05, 2019 05:49AM UTC

Droppable: drop event incorrectly triggered when dragging a draggable over a droppable onto a sortable

Reported by: avuori Owned by:
Priority: minor Milestone: 2.0.0
Component: ui.droppable Version: 1.8.6
Keywords: Cc: avuori
Blocked by: Blocking:
Description

When a draggable is connected with a sortable, and there is also a droppable involved, the droppable's drop event is erroneously triggered when the draggable is dragged quickly over the droppable (without ever releasing the mouse).

The example demonstrates the problem. It may not be reproducible instantly, but a few down/up drag movements should do it. An alert is shown when the droppable event is triggered.

The problem seems to be present only when the draggeble's helper is "clone".

<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js" type="text/javascript"></script> 
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.js"></script>
</head>
<body>

	<script>
	$(function() {
		$("tbody.sortable").sortable({});
		$(".draggable").draggable({
			helper: "clone",
			connectToSortable: "tbody.sortable"
		});
		$(".droppable")
		.droppable({drop: function () { alert("dropped"); } });
		$("td").disableSelection();
	});
	</script>
	<table>
		<tbody>
			<tr class="draggable ui-state-highlight"><td>Drag me down above the sortable, 
then quickly drag me up directly over and past the droppable</td></tr>
			<tr class="droppable ui-state-highlight"><td>Droppable</td></tr>
		</tbody>
		<tbody class="sortable">
			<tr class="ui-state-default"><td>Item 1</td></tr>
			<tr class="ui-state-default"><td>Item 2</td></tr>
			<tr class="ui-state-default"><td>Item 3</td></tr>
			<tr class="ui-state-default"><td>Item 4</td></tr>
			<tr class="ui-state-default"><td>Item 5</td></tr>
		</tbody>
	</table>
</body>
</html>
Attachments (1)
  • example.html (1.1 KB) - added by avuori November 03, 2010 04:13PM UTC.
Change History (13)

Changed November 03, 2010 04:28PM UTC by avuori comment:1

Tested with Chrome and Firefox 3.6.

Changed December 31, 2010 02:08AM UTC by be.davestein comment:2

I had the same issue on my site with very different markup. Was also using clone.

Changed March 12, 2011 10:46PM UTC by cnr comment:3

_comment0: $(".droppable") \ .droppable({drop: function () { \ if (!$(event.srcElement).hasClass("ui-draggable-dragging")) { return; } \ alert("dropped"); \ } \ }); \ \ will be solve your problem1299970024519568
_comment1: $(".droppable") \ .droppable({drop: function () { \ if (!$(event.srcElement).hasClass("ui-draggable-dragging")) { return; } \ \ alert("dropped"); \ } \ }); \ \ will be solve your problem1551764970286114
$(".droppable")
.droppable({drop: function () { 
   if (!$(event.srcElement).hasClass("ui-draggable-dragging")) { return; }

   alert("dropped"); 
} 
});

will be solve your problem

Changed March 15, 2011 04:28PM UTC by rjollos comment:4

_comment0: Replying to [comment:3 cnr]: \ > $(".droppable") \ > .droppable({drop: function () { \ > if (!$(event.srcElement).hasClass("ui-draggable-dragging")) { return; } \ > \ > alert("dropped"); \ > } \ > }); \ > \ > will be solve your problem \ \ \ Thanks for the tip! \ 1551764987537961

Replying to [comment:3 cnr]:

... will be solve your problem

Thanks for the tip!

Changed October 11, 2012 09:07PM UTC by scottgonzalez comment:5

milestone: TBD2.0.0

Changed October 29, 2012 04:21AM UTC by mikesherov comment:6

status: newopen
summary: Droppable's drop event triggered when dragging a draggable over the droppableDroppable: drop event incorrectly triggered when dragging a draggable over a droppable onto a sortable

confirmed on latest: http://jsfiddle.net/2aJh9/

Changed July 25, 2013 10:33AM UTC by discy comment:7

Because I needed the droppable to be droppable I fixed it by handling the drop event in the draggable:

var draggableOnDroppable;

.droppable({
over: function(event,ui) {
draggableOnDroppable = true;
},
out: function(event, ui) {
draggableOnDroppable = false;
});

.draggable({
stop: function (event, ui) {
if (draggableOnDroppable) //do something with draggable
}
});

Changed October 11, 2013 05:49PM UTC by pdore comment:8

Is there a known workaround?

Is there an alternative to using clone helper?

Changed October 11, 2013 05:53PM UTC by pdore comment:9

Is there a known workaround?

Is there an alternative to using clone helper?

Changed March 22, 2014 09:01AM UTC by rjollos comment:10

_comment0: Hello, the solution is simple. The drop can't be effective if you don't release the left mouse, so just detect the state of it, and bloc any action in droppable if you don't have left mouse released : \ \ \ var leftButtonDown; \ $(document).mousedown(function(e){ \ if(e.which === 1) leftButtonDown = true; \ }); \ $(document).mouseup(function(e){ \ if(e.which === 1) leftButtonDown = false; \ }); \ \ .droppable({ \ drop:function(e,ui){ \ \ if(leftButtonDown) return false; \ // Here code when really drop \ \ });1551764956663020

Hello, the solution is simple. The drop can't be effective if you don't release the left mouse, so just detect the state of it, and bloc any action in droppable if you don't have left mouse released :

var leftButtonDown;
$(document).mousedown(function(e){
   if(e.which === 1) leftButtonDown = true;
});
$(document).mouseup(function(e){
   if(e.which === 1) leftButtonDown = false;
});

.droppable({
  drop:function(e,ui){

    if(leftButtonDown) return false;
    // Here code when really drop

});

Changed July 09, 2014 10:22AM UTC by rjollos comment:11

_comment0: Replying to [comment:10 paulf66]: \ > Hello, the solution is simple. The drop can't be effective if you don't release the left mouse, so just detect the state of it, and bloc any action in droppable if you don't have left mouse released : \ > \ > \ > var leftButtonDown; \ > $(document).mousedown(function(e){ \ > if(e.which === 1) leftButtonDown = true; \ > }); \ > $(document).mouseup(function(e){ \ > if(e.which === 1) leftButtonDown = false; \ > }); \ > \ > .droppable({ \ > drop:function(e,ui){ \ > \ > if(leftButtonDown) return false; \ > // Here code when really drop \ > \ > }); \ \ \ This work-around works perfectly for FF & Chrome but IE10 triggers drop event first and then mouseup will get fire. So again this will not work on IE10. \ 1551764939277841

Replying to [comment:10 paulf66]:

Hello, the solution is simple. The drop can't be effective if you don't release the left mouse, so just detect the state of it, and bloc any action in droppable if you don't have left mouse released : ...

This work-around works perfectly for FF & Chrome but IE10 triggers drop event first and then mouseup will get fire. So again this will not work on IE10.

Changed April 01, 2015 06:51PM UTC by Morph3y comment:12

_comment0: I was able to find a quick workaround for those who are still interested. \ \ Basically the problem occurs only when during the drag over the sortable your draggable is in the position when its both over the droppable and sortable (highlighting both). \ \ Feel free to add a quick data() or just a flag to your ui.helper during the out() of the sortable which could be removed during the over() of the droppable. \ PS Make sure you don't allow your drop() on droppable to execute first time after the sortable out()! \ \ Example: \ \ self.contentTemplate.sortable({ \ ... bla bla bla ... \ out: function (event, ui) { \ // workaround for bug http://bugs.jqueryui.com/ticket/6259 \ ui.helper.data('overSortable', true); \ }, \ ... bla bla bla ... \ }); \ \ template.droppable({ \ ... bla bla bla ... \ over: function (event, ui) { \ // workaround for bug http://bugs.jqueryui.com/ticket/6259 \ ui.helper.removeData('overSortable'); \ }, \ drop: function (event, ui) { \ // workaround for bug http://bugs.jqueryui.com/ticket/6259 \ if (ui.helper.data('overSortable') != null) { \ ui.helper.removeData('overSortable'); \ return; \ } \ ... bla bla bla ... DO THE STUFF \ }, \ ... bla bla bla ... \ }); \ \ \ 1427914440031696
_comment1: I was able to find a quick workaround for those who are still interested. \ \ Basically the problem occurs only when during the drag over the sortable your draggable is in the position when its both over the droppable and sortable (highlighting both). \ \ Feel free to add a quick data() or just a flag to your ui.helper during the out() of the sortable which could be removed during the over() of the droppable. \ PS Make sure you don't allow your drop() on droppable to execute first time after the sortable out()! \ \ Example: \ \ self.contentTemplate.sortable({ \ ... bla bla bla ... \ out: function (event, ui) { \ // workaround for bug http://bugs.jqueryui.com/ticket/6259 \ \ ui.helper.data('overSortable', true); \ }, \ ... bla bla bla ... \ }); \ \ template.droppable({ \ ... bla bla bla ... \ over: function (event, ui) { \ // workaround for bug http://bugs.jqueryui.com/ticket/6259 \ \ ui.helper.removeData('overSortable'); \ }, \ drop: function (event, ui) { \ \ // workaround for bug http://bugs.jqueryui.com/ticket/6259 \ \ if (ui.helper.data('overSortable') != null) { \ ui.helper.removeData('overSortable'); \ return; \ } \ ... bla bla bla ... DO THE STUFF \ }, \ ... bla bla bla ... \ }); \ \ \ 1551764920664269

I was able to find a quick workaround for those who are still interested.

Basically the problem occurs only when during the drag over the sortable your draggable is in the position when its both over the droppable and sortable (highlighting both).

Feel free to add a quick data() or just a flag to your ui.helper during the out() of the sortable which could be removed during the over() of the droppable.

PS Make sure you don't allow your drop() on droppable to execute first time after the sortable out()!

Example:

self.contentTemplate.sortable({
... bla bla bla ...
    out: function (event, ui) {
       // workaround for bug http://bugs.jqueryui.com/ticket/6259

       ui.helper.data('overSortable', true);
    },
... bla bla bla ...
});

template.droppable({
... bla bla bla ...
    over: function (event, ui) {
        // workaround for bug http://bugs.jqueryui.com/ticket/6259

        ui.helper.removeData('overSortable');
    },
    drop: function (event, ui) {

        // workaround for bug http://bugs.jqueryui.com/ticket/6259

        if (ui.helper.data('overSortable') != null) {
            ui.helper.removeData('overSortable');
            return;
        }
    ... bla bla bla ... DO THE STUFF 
    },
... bla bla bla ...
});

Changed May 12, 2015 10:24AM UTC by Skaffen comment:13

I think I've pieced together which bits of code are interacting to cause this, plus also for "deactivate" to be triggered on droppables when you just drag a draggable back out of a connected sortable. The "drag" handler of the draggable's "connectToSortable" plugin has a bit which says:

// If it doesn't intersect with the sortable, and it intersected before,
// we fake the drag stop of the sortable, but make sure it doesn't remove
// the helper by using cancelHelperRemoval.

When you drag a draggable into a sortable and then out again as you drag out of the sortable that bit of code triggers and part of it calls:

sortable._mouseStop( event, true );

The _mouseStop of sortable then in turn runs this bit of code:

		//If we are using droppables, inform the manager about the drop
		if ($.ui.ddmanager && !this.options.dropBehaviour) {
			$.ui.ddmanager.drop(this, event);
		}

So it will call drop on the ddmanager, which doesn't seem desirable and can have two side effects.

The first is the one mentioned on this ticket - if your draggable happens to have moved over a droppable as you've moved out of the sortable then you'll see the drop event trigger (ddmanager.drop will check if the draggable intersects with a droppable and only call drop if it has).

The second one is one which prompted me to dig into this stuff which is that dragging a draggable into a sortable and then out of a sortable again will result in _deactivate being called on any droppables on the page:

				this._deactivate.call( this, event );

I spotted this because I was using the activeClass option of a droppable to highlight it where my draggable was also connected to a sortable. I was finding that dragging the droppable into and out of the sortable was causing the highlighting to go off.

This fiddle demonstrates:

http://jsfiddle.net/k0w71yb1/2/

On that fiddle drag the draggable downwards slowly and you'll see the drop area will highlight as you begin to drag. Continue to drag the draggable down through the sortable list and then out below the sortable list. You'll see that the highlighting of the drop area will cease and a "deactivate" will be logged to the console. Then stop dragging (let go of the mouse button) and you'll see a second "deactivate" will be logged to the console.

I would guess the fix could be for _mouseStop to be told that it's a fake drag stop and know to not trigger the "drop" event on the droppables in this circumstance, but I don't know enough about why the code is doing what it's doing to be sure!