
JQuery - using a Sortable and Droppable objects together.
Posted: Mon, Jun 22 2009 at 10:37amLate last week I was presented with a seemingly simple task - integrating a Droppable list of items with a Sortable list object. Basically the concept is to drag items from the Droppable (which have been initialized as Draggables) and be able to drop them into the Sortable where they can be either Sorted internally, or then dragged BACK out and placed back in the Droppable region.
As simple as this sounds, I promise you it wasn't. The difficulty here is that the Sortable object really uses a heavily modified Draggable Droppable integration... which means it's already bound to lots of the events that you would otherwise have control over with a standard Draggable object and Droppable object. This presents some interesting artifacts and event misfiring when atttempting to use the two of them in conjunction with the same items going to/from.
While the first apparent solution would be to simply use two Sortable lists, I should make it clear here that my requirement was to have the "Bin" of Draggable items be unsortable. It's design is simply to be a container where items can be dragged from, and dropped to. After some deliberation I decided to try a Sortable-Sortable integration since JQuery provides a "connectTo" feature in the intialization hash. While it worked as expected, I could find NO way to shunt the sorting that happens when dragging items from the bottom "Bin". After attempting to cancel event bubbling and other such ideas, I eventually abandoned it and moved back to trying to make the Sortable - Droppable function as expected.
So after about an hour of frustration and interesting Javascript behaviours, I stumbled apon a solution. The solution is to catch the Drop event in the Droppable region, get the ID of the ui.draggable object (which is the DOM object that's being dragged), DESTROY the sortable object (releasing all event handlers), append the JQuery object using the copied ID to the Droppable bin, then re-initialize the Sortable region and fire a manual update. Note that using this method completely circumvents the internal "update" even that is normnally fired from the Sortable object. It's also important to note here that the "helper" option in the Sortable intialization hash HAS to be set to "Original", as using "Clone" produces odd and erratic results in my testing.
Using this method I was able to successfully drag FROM a Droppable into a Sortable, and then from the Sortable back to the Draggable Droppable. Without destroying the Sortable region, this was not possible. Here's some sample code:
Droppable:
$(function()
{
$("#droppableDiv").droppable(
{
hoverClass: 'topDrop',
accept: 'div.draggable',
drop: function(event, ui)
{
//Grab the ID of the ui.draggable object
var id = ui.draggable.attr("id");
//Destroy the sortable and release all event handlers
$("#topSortable").sortable("destroy");
//Append the JQuery object using the ID attained above to the droppableDiv
$("#"+id).appendTo($(this));
resetSortable();
//Now fire any manual update routines
}
});
}
Sortable:
$("#topSortable").sortable(
{
appendTo: '#container',
opacity: 0.7,
revert: false,
scroll: true,
items: 'div.draggable',
helper: 'original',
opacity: 0.85,
zIndex: 55,
containment: '#container',
tolerance: 'intersect',
distance: 80,
cursor: 'move'
}).droppable(
{
// Notice the integration of Droppable here so that we can get to the exposed hoverClass
// feature which is not available to a sortable list.
hoverClass: 'topDrop',
accept: 'div.draggable',
tolderance: 'intersect'
});
Using this integration you can successfully combine the Sortable features, with the simplified Droppable object. For completions sake, here's the Draggable initialization as well:
Draggable:
$("div.draggable").draggable(
{
scroll: true,
helper: 'clone',
opacity: 0.80,
revert: 'invalid',
appendTo: '#container',
cursor: 'move',
connectToSortable: '#topSortable'
//Note the parameter above; This may not be necessary, but the documentation eludes that it helps.
});
I hope this helps someone else down the line!

Assassin Creed Revelations
Assassin's Creed: Brotherhood
Battlefield 3
COD: Black Ops
COD: Modern Warfare 3
Dirt 3
FIFA 12
Forza Motorsport 4
Gears of War 3
Ghost Recon Future Soldier
Halo Reach
Madden NFL 12
Marvel vs Capcom 3
MLB 2K11
Mortal Kombat
NHL 12
Street Fighter x Tekken
Super Street Fighter 4
Tekken 6
Starhawk
Uncharted 3
BF: Bad Company 2
Counter-Strike: Global Offensive
Halo Combat Evolved
League of Legends
Minecraft
Nexuiz
Quake III
Quake Live
StarCraft II
Team Fortress 2
Tribes Ascend
Unreal Tournament 99
FEAR 3
Homefront
Mario Kart


°