jQuery Sortable and Droppable

Viewed 38324

I want to have a list that is sortable, but I also want the elements in that list to be droppable to the divs I have defined as droppable. I can't seem to find a way to do it. Any ideas?

6 Answers

As far as I could tell, the issue with the previous code I posted is that the drop function of the droppable was getting called before the mouseup of the sortable, and since I rewrote the list the sortable was getting angry (for lack of better terms). That's somewhat a guess.

Looking at the final code:

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

var dropped = false;
var templateHtml;
$(document).ready(function(){

    setSortable();

    $("#droppable").droppable({
        activeClass: 'active',
        hoverClass:'hovered',
        accept:".drop",
        drop:function(event,ui){
            dropped = true;
            //alert(ui.draggable.text());
        }
    });

});

function setSortable(){
    $("#sortable").sortable({
        stop:function(event,ui){
            if(dropped){
                $("#sortable").sortable('destroy').html(templateHtml);
                dropped = false;
                setSortable();
            }
        }
    });

    $("#sortable li").addClass("drop").bind('mousedown',function(){
        templateHtml = $("#sortable").html();
    });
}

    </script>
    <style type="text/css">
    #sortable li{
        clear:both;
        float:left;
    }

    #droppable {
        clear:both;
        height:300px;
        width:400px;
        background-color:#CCC;
    }
    #droppable.active {
        background-color:#CFC;
    }
    #droppable.hovered {
        background-color:#CCF;
    }
    </style>

</head>
<body>

<ul id="sortable">
<li id="one">One</li>
<li id="two">Two</li>
<li id="three">Three</li>
<li id="four">Four</li>
<li id="five">Five</li>
<li id="six">Six</li>
</ul>

<div id="droppable">
Drop Here
</div>

</body>

Tons of quirks are involved here.

I tried to save the #sortable html on the start event of sortable, but that get's called after all of the ui-css gets applied, and ended up placing list elements in crazy places. So, I needed to use the mousedown function on the LIs.

The setSortable is in a function because the stop event rewrites the sortable, which is "recursive" I guess. Not sure the exact terminology here, but we can go with annoyingly confusing.

Fortunately, the droppable's drop function gets called before the sortables stop function, so I was able to set a global "dropped" variable that was used to see if the element was dropped.

I'm still surprised this wasn't easier to do, I thought jQuery would have functions to handle it a lot better. Perhaps I'm missing something?

I've spent all day on this, and I've gotten a lot closer, but still not doing as well as I'd like. I now have the functionality I need, but a Javascript error is getting thrown.

The issue is getting the sortable list to return to its previous position if the element is dropped in the droppable, rather than in the list. Currently, I'm saving the html onmousedown, then rewriting the html in the drop function of the droppable. This works, but its giving me a jquery variable is null error. Can anyone find a better solution?

Code:

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

var templateHtml;
$(document).ready(function(){

    $("#sortable").sortable();
    $("#sortable li").addClass("drop").bind('mousedown',function(){
        templateHtml = $("#sortable").html();
    });
    $("#droppable").droppable({
        activeClass: 'active',
        hoverClass:'hovered',
        accept:".drop",
        drop:function(event,ui){
            $("#sortable").sortable('destroy').html(templateHtml);
            $("#sortable").sortable();
            $("#sortable li").addClass("drop").bind('mousedown',function(){
                templateHtml = $("#sortable").html();
            });          
        }
    });

});

    </script>
    <style type="text/css">
    #sortable li{
        clear:both;
        float:left;
    }

    #droppable {
        clear:both;
        height:300px;
        width:400px;
        background-color:#CCC;
    }
    #droppable.active {
        background-color:#CFC;
    }
    #droppable.hovered {
        background-color:#CCF;
    }
    </style>

</head>
<body>

<ul id="sortable">
<li id="one">One</li>
<li id="two">Two</li>
<li id="three">Three</li>
<li id="four">Four</li>
<li id="five">Five</li>
<li id="six">Six</li>
</ul>

<div id="droppable">
Drop Here
</div>

</body>
Related