Programmatically moving elements

May 26, 2011 at 7:16 PM

Thanks to everyone who has contributed to DragSort, it's quite lovely.

I have a list in which you can drag'n'drop things to re-order items using DragSort. Each item has buttons for "Up" and "Down" which are intended to move the item up or down in the list. I am now about to implement the functionality for those buttons and had intended to delete and re-enter the DOM content appropriately in a custom JavaScript function that gets called when those buttons are pressed.

My question is: Can this be done with DragSort using internal functionality, or am I stuck editing the DOM myself?

P.S.: I know how to edit the DOM so that's not a problem, I'm merely asking to save time. :)

Coordinator
May 27, 2011 at 11:39 PM
Edited May 29, 2011 at 3:05 AM

Sure, you can find documentation on what jquery provides here:
http://api.jquery.com/category/manipulation/dom-insertion-outside/

Here's an example:

<style type="text/css">	
  #list1 li:first-child .upArrow,
  #list1 li:last-child .downArrow { display:none; }
</style>

<ul id="list1">
  <li><div>1<a class="upArrow">&#8593;</a><a class="downArrow">&#8595;</a></div></li>
  <li><div>2<a class="upArrow">&#8593;</a><a class="downArrow">&#8595;</a></div></li>
  <li><div>3<a class="upArrow">&#8593;</a><a class="downArrow">&#8595;</a></div></li>
  <li><div>4<a class="upArrow">&#8593;</a><a class="downArrow">&#8595;</a></div></li>
</ul>

<script type="text/javascript">	
  $(".upArrow, .downArrow", "#list1").live("click", function() {
    var item = $(this).closest("li");
    if ($(this).is(".upArrow")) //move up
      item.insertBefore(item.prev());
    else //move down
      item.insertAfter(item.next());
  });
</script>

First thing to be aware of if you are using dragsort as well, if you click on the A tag to move LI up or down you're going to trigger the dragsort code and the arrow onclick won't fire. To solve this dragsort provides an option called dragSelectorExclude which by default is set to "input, textarea, a[href]" so in my example it will conflict since the A tags have no href attribute. To solve this set the dragSelectorExclude to ".upArrow, .downArrow", if you are using a button i.e. input then you are all good. Alternatively if you have an icon they need to click to drag instead of the whole list item, then setting dragSelector to that icon will also solve the potential conflict.

Next thing, since we don't want the up arrow to appear if the list item is in the first position or the down arrow if the list item is in the last position, I am using css to hide the arrows. "#list1 li:first-child" means the first tag below #list1 if it's an LI. IE6 doesn't support this css but we've stopped supporting that browser in our sites, and IE7 does support that css so it is safe to use, and a bit easier than writing javascript to show or hide the arrows.

What "$('.upArrow, .downArrow', '#list1').live('click', handler)" does is an onclick handler is attached to #list1, and every time it fires, the actual element inside the list that was clicked is compared to the selector ".upArrow, .downArrow" and if it matches it fires our handler. This is useful for long lists because instead of the browser having to maintain separate handlers for every button in the list it only needs to maintain one which reduces load (although our list is quite short and would make little difference). It's also helpful if you have ajax or some other javascript routine adding new list items as you now don't need to worry about attaching onclick handlers to these new buttons.