Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Reorganisable List with JavaScript

4.80/5 (2 votes)
19 Nov 2013CPOL1 min read 13.4K   50  
Example of how to make a list whose items can change positions

Introduction

This tip shows how one can make a <ul>'s <li>s can be reorganised by "swapping" positions between different <li>s as the mouse is dragged over them.

A working example can be found here (pure JavaScript version) or here (jQuery version).

This currently works on Google Chrome well. I cannot speak for other browsers.

Using the Code

The "swap" is actually done by taking the content of one <li> and exchanging it with another one. The HTML for this looks as follows:

HTML
<ul>
    <li>
        <span class="item">Kevin</span>    <!-- The content -->
        <span class="drag"></span>    <!-- The drag icon -->
    </li>
    ...
    <li>
        <span class="item">Roe</span>
        <span class="drag"></span>
    </li>
</ul> 

The phantom list item that follows the mouse as you hold down the mouse and drag is positioned above the <ul> and positioned absolutely in the CSS;

HTML
<div id="phantom">
    <span class="item">Amygdala</span>
    <span class="drag"></span>
</div> 

The JavaScript is configured to listen for a mousedown event on the drag icon for any list item. This sets a flag to true so that any mousemove event triggered any <li> triggers a "swap" between the <li>s. Once the mouseup event which is attached to the <ul> element is triggered, the flag is negated to false preventing any other swaps. The code looks like this:

JavaScript
window.onload = function() {
    var index = -1;        //This is the item index of the item being moved
    var over = -1;        //This is the new position
    var item = '';        //This is the current items content
    var swap = '';        //This is the content of the item it will replace
    var move = false;    //This determines if we can change two items' positions

    var container = document.getElementById('container');        //This is the parent of our list
    var ul = document.getElementById('container').children[2];    //This is the list of items
    var phantom = document.getElementById('phantom');            //This is the opaque copy of the item being moved

    phantom.onmousemove = function(e) { e.preventDefault(); }    //This prevent the mouse from highlighting stuff

    ul.onmouseup = function(e) {
    //This function is called when the action of shifting positions is done when dragging items
        phantom.style.display = 'none';
        move = false;
    }

    for(var i = 0; i < ul.children.length; i++) {
            ul.children[i].children[1].onmousedown = function(e) {    
             //This event is attached to the drag icon in the list item
            move = true;
            index = Array.prototype.indexOf.call(ul.children, 
            	e.target.parentElement);    //Get the index of the item in question
            item = ul.children[index].children[0].innerHTML; //Get it's content as well
            phantom.children[0].innerHTML = item; //Give the phantom item the same content
            phantom.style.display = 'block';      //Display the phantom item
        }
    }

    for(var i = 0; i < ul.children.length; i++) {
        ul.children[i].onmouseover = function(e) { //This function ensures all list item positions can be swapped
            if(Array.prototype.indexOf.call(ul.children, 
            	e.target) != -1 && move) {    //Ensure you get the list item position and can move
                over = Array.prototype.indexOf.call(ul.children, e.target); // The new position
                swap = ul.children[over].children[0].innerHTML;   //Get the current content of the new position
                ul.children[index].children[0].innerHTML = swap;  //Change the content of the item in question
                ul.children[over].children[0].innerHTML = item;   //Change the content of the other item i.e the swap
                index = over;   // This ensure that your positions swap every time your move the mouse
            }
        }
    }

    ul.onmousemove = function(e) {    //This function displays the phantom list item appropriately
        e.preventDefault();
        if(index != -1) {
            //Its position is based on the containers offset top and 
            //it should be some pixels below the cursor hence the 5
            var top = e.pageY - parseInt
            (document.getElementsByTagName('ul')[0].getBoundingClientRect().top) + 5;
            phantom.style.marginTop = top + 'px';
        }    
    }
}

History

Update: 19-11-2013

I made a few small changes to the code to support Internet Explorer 7+. The changes are just work arounds so the logic remains the same. I unfortunately still can't tell what's going on with Mozilla but if I get it, I'll make the necessary changes.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)