Static Items in 2D list

Jun 16, 2010 at 7:50 AM


I just stumbled accross this fantastic resource while looking for an upgrade option for our existing tool-man solution, I was wondering if it is possible to do the following:

Using your "2D list with drag and drop between lists" example, where you can freely move items between the left and right lists. We need to keep this functionality but also have a number of static li elements that remain in the left hand list. So effectively when these are dragged to the right they are copied - not moved, and if they are dragged back to the left, the copies are removed from the container altogether.

I have a sneaky feeling that Im going to have to write my own library to do so, but I thought I would post a comment on the off chance that it might be possible.



Jun 16, 2010 at 11:14 AM

If you don't mind it disappearing from the left hand list temporarily when you drag the item to the right hand list until it's dropped, it can all be done externally to the dragsort code like below. If you do mind then we will need to look at modifying the dragsort code to achieve your desired behaviour.

$("#list1, #list2").dragsort({ dragSelector: "div", dragBetween: true, dragEnd: saveOrder, placeHolderTemplate: "<li class='placeHolder'><div></div></li>" });

$("#list1 > li").each(function(i) { $(this).attr("list1", i); });
$("#list2 > li").attr("list2", true);

function saveOrder() {
	//restore lost item
	$("#list2 > li[list1]").each(function() {
		var idx = parseInt($(this).attr("list1"));
		if (idx >= $("#list1 > li").size())
			$("#list1 > li:eq(" + idx + ")").before($(this).clone());
	//remove extra item
	$("#list1 > li[list2]").remove();
	//reset order
	$("#list1 > li").each(function(i) { $(this).attr("list1", i); });
	$("#list2 > li").attr("list2", true);


Jun 16, 2010 at 1:48 PM

Oops, after re-reading your question it sounds like your static list is acting more like a toolbar in which case it wouldn't make sense to be able to re-order it. Here's a different approach that only allows re-ordering of the list on the right:

$("#list2").dragsort({ dragBetween: true, dragEnd: saveOrder, placeHolderTemplate: "<li class='placeHolder'><div></div></li>" });

function saveOrder() {
	var data = new Array();
	$("#list2 li").each(function(i, elm) { data[i] = $(elm).children().html(); });

//copy clicked item in list1 across to list2 and simulate mouseclick on copied item to trigger dragsort
$("li", $("#list1")[0]).css("cursor", "pointer").live("mousedown", function(e) {
	var elm = $("#list2 li:last")[0];
	var coor = $(elm).offset();
	$(elm).trigger({ type:"mousedown", button:0, pageX:parseInt(coor.left + $(elm).width()/2.0), pageY:parseInt( + $(elm).height()/2.0), target:elm });
	$(document).trigger({ type:"mousemove", pageX:e.pageX, pageY:e.pageY });
	return false; //stop moz text selection

//if items from list2 are dragged above list1 remove from dom
$("li", $("#list2")[0]).live("mouseup", function(e) {
	var area = $("#list1");
	var coor = area.offset();
	var elm = this;
	var bottom = area.height() > 0 ? area.height() + : + area.width() * area.children(":first").height() / area.children(":first").width();
	//if mouse cursor above list1
	if (e.pageX >= coor.left && e.pageX <= coor.left + area.width() && e.pageY >= && e.pageY <= bottom)
		window.setTimeout(function() { $(elm).remove(); }, 0); //use timeout to run after dragsort's dropItem function


Jun 16, 2010 at 2:27 PM


Thanks mcm_ham, I was only looking for some pointers, this is much appreciated!!

You've given me plenty to work with here, but I think your original solution was closer to what I was after, where List1 contains 2 types of items (with attribute "Static" either true or false),
when dragged and dropped into List2 - items with Static=false are moved (normal behaviour) and items with Static=true are copied/cloned into List2. When dragNdrop back to List 1 Static=false
items are moved (normal behaviour), but when we dragNdrop Static=true items, they are removed from List2 (as they will already exist in List1)

I'll have a play with your generously donated code, and post back with any progress I make for future googlers ;)

Thanks again!!!

Jun 16, 2010 at 10:21 PM


Hi again,
For anyone who might wonder how i got this working (with and incredible amount of help from mcm_ham) :
ul id="list1"> <li id="1" static="true"><div>1 static</div></li> <li id="2" static="true"><div>2 static</div></li> <li id="3" static="true"><div>3 static</div></li> <li id="4" static="true"><div>4 static</div></li> <li id="5"><div>5 test</div></li> <li id="6"><div>6 test</div></li> <li id="7"><div>7 test</div></li> <li id="8"><div>8 test</div></li> <li id="9"><div>9 test</div></li> </ul> <ul id="list2"> <li id="10"><div>10 test</div></li> <li id="11"><div>11 test</div></li> <li id="12"><div>12 test</div></li> <li id="13"><div>13 test</div></li> <li id="14"><div>14 test</div></li> <li id="15"><div>15 test</div></li> <li id="16"><div>16 test</div></li> <li id="17"><div>17 test</div></li> <li id="18"><div>18 test</div></li> </ul>



<script type="text/javascript">
		$("#list1, #list2").dragsort({ dragSelector: "div", dragBetween: true, dragEnd: saveOrder, placeHolderTemplate: "<li class='placeHolder'><div></div></li>" });

		function labelItems() {
		    $("#list1 > li").each(function(i) { $(this).attr("list", "list1"); });
		    $("#list2 > li").each(function(i) { $(this).attr("list", "list2"); });
		function saveOrder() {

		    //ignore if moving within own container
		    if ($(this).parent().attr("id") != $(this).attr("list")) {
		        //if static and moving to list2 (from list1) then clone in list1
		        if (($(this).attr("static") == "true") && ($(this).parent().attr("id") == "list2")) {
		        //if static and moving to list1 (from list2) then remove
		        if (($(this).attr("static") == "true") && ($(this).parent().attr("id") == "list1")) {

	                // label items in each so can assertain the source of the dragged item



Thanks again mcm_ham!!!

Jun 17, 2010 at 12:22 PM

Sorry to be a pain, but has anyone implemented a 3D list, where you can drag between A and C, B and C, but not A and B?

I thought it would simply be a case of specifying something like:


$("#listA, #listC").dragsort({ dragSelector: "div", dragBetween: true, dragEnd: saveOrder, placeHolderTemplate: "<li class='placeHolder'><div></div></li>" });

$("#listB, #listC").dragsort({ dragSelector: "div", dragBetween: true, dragEnd: saveOrder, placeHolderTemplate: "<li class='placeHolder'><div></div></li>" });


But that left me with some strange behaviour where the placeHolder appears twice for the duration of the mouse button being clicked, im assuming its down to where its retrieving the
placeholder item in the grabItem function (where its picking up the 2 registrations of placeholdertemplate above):


 list.placeHolderItem ="height", list.draggedItem.height()).attr("placeHolder", true);

Before I delve deeper, i was wondering if anyone had tried this before?




Jul 17, 2010 at 3:34 AM
Edited Jul 17, 2010 at 3:38 AM

Sorry for the late reply, been a bit busy lately. Here's a quick approach (it uses indexes rather than selectors which would be nicer) to get this working:

$("#listA, #listB, #listC").dragsort({ dragBetween: true, dragBetweenExclude: [[1],[0],[]] });

In jquery.dragsort.js file in swapItems method:

for (var i = 0; ei == -1 && opts.dragBetween && i < lists.length; i++) {
	if (opts.dragBetweenExclude && opts.dragBetweenExclude.length > i && $.inArray($(lists).index(list), opts.dragBetweenExclude[i]) != -1)

Where index 0 is #listA in the selector and index 1 is #listB, and dragBetweenExclude[0] is the array containing the list of indexes of the lists to exclude when dragging an item in #listA and so on.

Aug 30, 2013 at 5:16 PM
this is almost exactly what I need.. I'm wondering if there's a way to keep list1's static items in a specific order (i.e. after it clones, reorder them automatically using an each and a custom tag with sort order or something to that effect)