Disabling jQuery drag and drop while scrolling the contents of a dragged item

Usually I do not ask this question / answer, but I decided that I would do it, since I saw this question more than 20 times, and not a single answer actually works. In short, the problem is that if you have scrollable content ( overflow: auto; anywhere in the jQuery draggable element, when you click and drag the scroll bar, the draggable parent container drags along with it. So I spent some time developing a solution .

Here is an example of some html that will present this problem:

 <div class="draggable" style="width:100px;height:100px;"> <div id="content" style="width:80px;height:80px;overflow:auto;"> Nullam quis risus eget urna mollis ornare vel eu leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam id dolor id nibh ultricies vehicula ut id elit. </div> </div> 

A typical way to initialize an item to be dragged is something like this:

 $(".draggable").draggable() 
+7
source share
4 answers

The solution is to bind to the scroll event on the elements of your initialization and any of these elements. Then, when any of the children invokes a scroll command, find all the draggable parents of this element and set the scrolling data element in this element.

In the current version of jQuery UI (1.8.16), the initial event always fires when you click the mouse on the scroll bar and updates the tree, so this solution works very well when testing.

 $(".draggable").draggable({ start: function() { // if we're scrolling, don't start and cancel drag if ($(this).data("scrolled")) { $(this).data("scrolled", false).trigger("mouseup"); return false; } } }).find("*").andSelf().scroll(function() { // bind to the scroll event on current elements, and all children. // we have to bind to all of them, because scroll doesn't propagate. //set a scrolled data variable for any parents that are draggable, so they don't drag on scroll. $(this).parents(".ui-draggable").data("scrolled", true); }); 

For your viewing pleasure, I have included jsfiddle problems.

+4
source

I propose a solution based on a mixture of [1] and a solution provided by PriorityMark. This solution works more reliably, and I think it is even more efficient.

 $(".draggable").draggable({ start: function(event) { var content = $(this).children('.content'); // if we're scrolling, don't start and cancel drag if (event.originalEvent.pageX-content.offset().left > content.innerWidth()) { console.log('should-cancel'); $(this).trigger("mouseup"); return false; } } }); 

To do this, I slightly adjusted the DOM example (but this should not be a big problem):

 <div class="draggable" style="width:100px;height:100px;overflow:auto;"> <div class="content" style="width:80px;height:80px;"> Nullam quis risus eget urna mollis ornare vel eu leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam id dolor id nibh ultricies vehicula ut id elit. </div> </div>​ 

Note that here the draggable div has an overflow , not a content div. For the solution, this does not really matter, but I do not want to add an additional div level, since this does not have to be done.

Here is the jsfiddle .

[1] - listen for mouse events ... except for div overflow: scrollbar scrollbar?

+6
source

I was looking for this problem and found a smaller solution that works great for me, and I want to share it. My solution is to stop distributing the "mousedown" event on the child / content. No mousedown means no drag;)

 $(".draggable").draggable(); $("#content").mousedown(function(event) { event.stopPropagation(); }); 
+1
source

This is a fairly simple solution, but it has one error. When it is configured to scroll, a second drag is required to drag an item.

0
source

All Articles