jQuery ui draggable elements not 'draggable' outside of scrolling div

43,880

Solution 1

Are you going to allow more than one instance with your draggable objects? then use the helper and append option:

$(".tag_cell").draggable({ 
  helper: 'clone',
  appendTo: 'div#myHelperHolder'
});

Then in your css you can set the zindex of div#myHelperHolder to be 999. If not, then try just using the zindex option:

$(".tag_cell").draggable({ 
  zIndex: 999
});

I would also consider setting addClasses to stop the plugin from adding all those annoying classes that waste processor speed.

UPDATE: I HAVE A NEW SOLUTION

Okay after playing with it for a bit I came up with this: the scroll option doesn't stop the child from being hidden with overflow. I've read some other posts and I cant find a single solution. But I came up with a bit of a work-a-round that gets the job done.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript">
    google.load("jquery", "1.4.0");
    google.load("jqueryui", "1.7.2");   
    google.setOnLoadCallback(OnLoad);
    function OnLoad(){
        var dropped = false;
        $(".tag_cell").draggable({ 
            addClasses: false,
            revert: 'invalid',
            containment: '#tagFun_div_main',
            helper: 'clone',
            appendTo: '#tagFun_div_helper',
            start: function(event, ui) {
                dropped = false;
                $(this).addClass("hide");
            },
            stop: function(event, ui) {
                if (dropped==true) {
                    $(this).remove();
                } else {
                    $(this).removeClass("hide");
                }
            }
        });
        $("#tf_dropBox").droppable({
            accept: '.tag_cell',
            hoverClass: 'tf_dropBox_hover',
            activeClass: 'tf_dropBox_active',
            drop: function(event, ui) {
                dropped = true;
                $.ui.ddmanager.current.cancelHelperRemoval = true;
                ui.helper.appendTo(this);
            }
        });
    }
    </script>
    <style>
        div#tagFun_div_main { display:block; width:800px; height:400px; margin:auto; padding:10px; background:#F00; }
        div#tf_div_tagsReturn { display:block; width:200px; height:100%; float:left; overflow:auto; background:#000; }
        div#tf_div_tagsDrop { display:block; width:200px; height:100%; float:right; background:#0F0; }
        div#tf_dropBox { display:block; width:100%; height:250px; background:#F0F; }
        span.tag_cell { display:block; width:25px; height:25px; margin:1px; float:left; cursor:pointer; background:#0FF; z-index:99; }
        span.tag_cell.hide { display:none; }
        div#tf_dropBox.tf_dropBox_hover { background:#FFF !important; }
        div#tf_dropBox.tf_dropBox_active { background:#333; }
    </style>
</head>
<body>
    <div id="tagFun_div_main">
        <div id="tf_div_tagsReturn">
            <span class="tag_cell"></span>
            <span class="tag_cell"></span>
            <span class="tag_cell"></span>
            <span class="tag_cell"></span>
            <span class="tag_cell"></span>
            <span class="tag_cell"></span>
            <span class="tag_cell"></span>
            <span class="tag_cell"></span>
            <span class="tag_cell"></span>
            <span class="tag_cell"></span>
            <span class="tag_cell"></span>
        </div>
        <div id="tf_div_tagsDrop">
            <div id="tf_dropBox"></div>
        </div>
    </div>
    <div id="tagFun_div_helper">
    <!-- this is where the helper gets appended for temporary use -->
    </div>
</body>
</html>

I pasted my entire code so you can try it out. Here is a brief description: When you start to drag an item it hides the original, clones it, then appends the clone to a container outside the overflow area. Once dropped it removes the original and moves the clone into the drop zone. Great so now we have fixed that overflow issue but run into some others. When you drop the clone item into the drop zone it disappears. To stop that from happening I used this method:

$.ui.ddmanager.current.cancelHelperRemoval = true;

Now we have stopped the helper from being removed but it remains in "div#tagFun_div_helper" while the original draggable item has reappeared.

ui.helper.appendTo(this);

This will transfer the helper from "div#tagFun_div_helper" into our drop zone.

dropped = true;

This will tell our stop function to delete the original item from the group instead of removing the ".hide" class. Hope that helps!

Solution 2

In my case, this solved it for me and works perfectly!

UPDATED

$(".amigo").draggable({
            revert: "invalid" ,
            helper: function(){
                $copy = $(this).clone();
                return $copy;},
            appendTo: 'body',
            scroll: false
        });
Share:
43,880
Seth
Author by

Seth

Updated on July 31, 2020

Comments

  • Seth
    Seth almost 4 years

    I have many elements (floating href tags) in a div with a set height/width, with scroll set to overflow: auto in the CSS.

    This is the structure of the divs:

    <div id="tagFun_div_main">
    <div id="tf_div_tagsReturn">
        <!-- all the draggable elements go in here, the parent div scolls -->
    </div>
    <div id=" tf_div_tagsDrop">
        <div id="tf_dropBox"></div>
    </div></div>
    

    the parent div's, 'tf_div_tagsReturn' and 'tf_div_tagsDrop' will ultimately float next to each other.

    Here is the jQuery which is run after all of the 'draggable' elements have been created with class name 'tag_cell', :

    $(function() {
        $(".tag_cell").draggable({ 
            revert: 'invalid', 
            scroll: false,
            containment: '#tagFun_div_main'
        });
        $("#tf_dropBox").droppable({
            accept: '.tag_cell',
            hoverClass: 'tf_dropBox_hover',
            activeClass: 'tf_dropBox_active',
            drop: function(event, ui) {
                GLOBAL_ary_tf_tags.push(ui.draggable.html());
                tagFun_reload();
            }
        });
    }); 
    

    as I stated above, the draggable elements are draggable within div 'tf_div_tagsReturn', but they do not visually drag outside of that parent div. worthy to note, if I am dragging one of the draggable elements, and move the mouse over the droppable div, with id 'tf_dropBox', then the hoverclass is fired, I just can't see the draggable element any more.

    This is my first run at using jQuery, so hopefully I am just missing something super obvious. I've been reading the documentation and searching forums thus far to no prevail :(

    UPDATE:

    many thanks to Jabes88 for providing the solution which allowed me to achieve the functionality I was looking for. Here is what my jQuery ended up looking like:

    $(function() {
        $(".tag_cell").draggable({ 
            revert: 'invalid', 
            scroll: false,
            containment: '#tagFun_div_main',
            helper: 'clone',
            start : function() {
            this.style.display="none";
            },
            stop: function() {
            this.style.display="";
            }
        });
        $(".tf_dropBox").droppable({
            accept: '.tag_cell',
            hoverClass: 'tf_dropBox_hover',
            activeClass: 'tf_dropBox_active',
            drop: function(event, ui) {
                GLOBAL_ary_tf_tags.push(ui.draggable.html());
                tagFun_reload();
            }
        });
    }); 
    
  • Seth
    Seth over 14 years
    thank you for your reply. i didn't go with using helper/clone but i did set zindex to 999, the problem is still occurring. i really don't know what the problem is, i'm starting to wonder if this is possible, but i have to imagine people contain draggable elements in scrolling div's all the time. thanks for the addClasses suggestion, i implemented that. please share any other suggestions/thoughts you might have on this scrolling issue.
  • Justin Bull
    Justin Bull over 14 years
    I have updated my response to include a new solution. check it out. Also I noticed one of your div id's have a space before the first letter <div id=" tf_div_tagsDrop">. I don't think it was affecting anything, but I just thought you should know :-)
  • Seth
    Seth over 14 years
    Jabes - thank you for your solution, i appreciate the time you spent working on this. i ended up using a modified version of your approach to achieve the functionality i am looking for. i dont need to worry about the element remaining displayed in the droppable div after it is dropped. in regards to the div containing the draggable elements, i am refreshing it after one of those elements has been dropped, with new elements based on what was just dropped. i am updating my original question with the jquery i ended up going with, thank you very much for answering my questioN!
  • Justin Bull
    Justin Bull over 14 years
    I'm glad I was able to help Stu. I would appreciate an up-vote if you could spare one :)
  • Trevor North
    Trevor North over 12 years
    I have the same issue and have applied code similar to Justin's solution above but note that after dragging an element into the droppable, it appends style=postition:absolute and a top and left coordinate. The element is then not draggable elsewhere unless i refresh the page - Is there a way to ensure the helper clone gets the same properties as the original so it is also draggable ? TIA
  • George
    George over 12 years
    slightly modified: helper: function () { $copy = $(this).clone(); $copy.css({"list-style":"none","width":$(this).outerWidth()}‌​); return $copy; }
  • anewcomer
    anewcomer about 12 years
    Yup, this is what I needed as well. I was trying to move a draggable div outside of a Telerik MVC grid in scrollable-paging mode, and the appendTo and scroll options above did the trick.
  • user2173353
    user2173353 almost 10 years
    Does $copy mean something special to JQueryUI? Why not return $(this).clone(); ?
  • PeterToTheThird
    PeterToTheThird almost 10 years
    clone() will not copy over the CSS attributes that have been applied to the source node. If you want to be able to preserve visual elements like width and padding, you have to use re-apply them. The use of $copy is just a naming convention for a variable, with the $ commonly used to indicate that the variable refers to a jQuery object.
  • Peril Ravine
    Peril Ravine over 9 years
    I've found there is a huge difference in whether you use single or double quotes. appendTo: 'body' does not work for me but appendTo: "body" does. Likewise helper: 'clone' does nothing but helper: "clone" works better than what you did here.
  • poshest
    poshest over 5 years
    What if I also want to be able to scroll within the overflowed div while dragging? Here's my full question.