Drag and Drop table content with JavaScript

Content of HTML table cells can be dragged to another cell or another table. It isn’t difficult to define onMouseMove handler and change top / left element styles to move the object. In case with tables, you will have to determine somehow target cell. Attaching onMouseOver handler on TD elements will not work, because browser doesn’t fire events to the elements below the dragged object.

Anyway, after taking care of the current scroll position and calculating TD positions, REDIPS.drag should work in recent major browsers like Google Chrome, Firefox, Safari, Internet Explorer, Opera and mobile devices as well. Click on image below, will open live demo where you can drag green, blue or orange bordered DIV elements, change properties (radio button and check-boxes) and click on “Save” button.

Download latest version redips2.tar.gz


REDIPS.drag example01

In this example “Save” button will scan table content, create query string and send to PHP page. Demo shows how to collect content and accept parameters on the server side. More about accepting parameters you can read at Reading multiple parameters in PHP. “Clone” elements (orange in this demo) will be duplicated first because of “redips-clone” keyword contained in class name. If you drop object on cell named “Trash”, object will be deleted from the table (with or without confirmation). Library has built in autoscroll and option to forbid landing to non empty cells or cells named with class “redips-mark”. Table can contain rowspan / colspan TDs and different background color for every cell.

Here are minimal steps to enable content dragging in table:

  • put <script type=”text/javascript” src=”redips-drag-min.js”></script> to the head section
  • initialize REDIPS.drag library: <body onload=”REDIPS.drag.init()”>
  • place table(s) inside <div id=”redips-drag”> to enable content dragging
  • place <div class=”redips-drag”>Hello World</div> to the table cell

Other features of REDIPS.drag library:

  • methods and data structure are defined in namespace (easier integration with other JS frameworks)
  • all JavaScript code is checked with ESLint
  • REDIPS.drag documentation generated with JsDoc Toolkit
  • drag and drop table rows
  • movable DIV element can contain other HTML code (images, forms, tables …)
  • forbidding or allowing TDs marked with class name “redips-mark”
  • option to define exceptions and allow dropping certain DIV elements to the marked cell
  • option to define single content cell on the table declared with “multiple” drop option
  • cloning
    • for unlimited cloning add “redips-clone” class name to the DIV object
      <div class=”redips-drag redips-clone”>Hello World</div>
    • to limit cloning and transform last object to the ordinary movable object add ‘climit1_X’ class name
      <div class=”redips-drag redips-clone climit1_4″>Hello World</div>
    • to limit cloning and transform last object to immovable object add ‘climit2_X’ class name
      <div class=”redips-drag redips-clone climit2_4″>Hello World</div>
    • where X is integer and defines number of cloned elements (in previous examples, each climit will allow only 4 cloned elements)
  • unlimited nested tables support
  • dropping objects only to empty cells
  • switch cell content
  • switching cell content continuously
  • overwrite TD content with dropped element
  • shift table content
  • table cell with “redips-trash” class name becomes trashcan
  • enabled handlers to place custom code on events: changed, clicked, cloned, clonedDropped, clonedEnd1, clonedEnd2, dblClicked, deleted, dropped, droppedBefore, finish, moved, notCloned, notMoved, shiftOverflow, relocateBefore, relocateAfter, relocateEnd, rowChanged, rowClicked, rowCloned, rowDeleted, rowDropped, rowDroppedBefore, rowDroppedSource, rowMoved, rowNotCloned, rowNotMoved, rowUndeleted, switched and undeleted
  • deleting cloned DIV if the cloned DIV is dragged outside of any table
  • enabling / disabling dragging
  • animation (move element/row to the destination cell/row)
  • added support for touch devices (touchstart, touchmove, touchend)

How REDIPS.drag works?

Script will search for DIV elements (with class name “redips-drag”) inside tables closed in <div id=”redips-drag”> and attach onMouseDown event handler. When user clicks with left mouse button on DIV element, onMouseMove and onMouseUp handlers will be attached to the document level.

While dragging DIV element, script changes its “left” and “top” styles. This is function of the onMouseMove handler. When user releases left mouse button, onMouseUp event handler will unlink onMouseMove and onMouseUp event handlers. This way, browser will listen and process mousemove events only when DIV element is dragged.

As I mentioned, onMouseDown is defined on the elements you want to drag. Elements beneath the dragged object will not be able to catch onMouseOver event. Why? Because you are dragging object and that object only can catch the onMouseOver event.

So, to detect destination table cells, script calculates all cell coordinates (with scroll page offset) and store them to the array. Array is searched inside onMouseMove handler and after left mouse button is released, DIV will drop to the current (highlighted) table cell.

In redips2.tar.gz package you will find many examples including example of how to save/recall table using PHP and MySQL. Package also contains and redips-drag-min.js – a compressed version of REDIPS.drag library (compressed with Google Closure Compiler).

Happy dragging and dropping!

1,195 thoughts on “Drag and Drop table content with JavaScript”

  1. Is there any conflict in jQuery AJAX with your script. Because in your script already the AJAX callback function is there.

    I just declared the REDIPS.drag.init() and included the file redips-drag-min.js in the page(main.php). But I had loaded the content for drop and drag from some other page(example.php).

    Like (“div”).load(“example.php”); or AJAX call.

    But in this method not working.

    If I put the example.php code in the same page(main.php) means its working. when I call the page example.php from the main.php means drag and drop not working.

  2. @Prabu – I think the problems is due to initialization. If you load DIV drag container with tables dynamically to your page, you should call REDIPS.drag.init() after table content is loaded. I suppose that initialization can be done inside AJAX callback function. If you can let me to peek to your code or you can prepare and send me offline example I will gladly help. Did you try to use Web inspector tool? It’s very handy and can help in finding a problem.

  3. Hi,
    How can i use both horizontal and vertical drag and drop in example 21 of use it.

  4. @prabu – It’s possible to change shift_option public property within event handlers. So, you can use myhandler_dropped_before event handler to set shift_option dynamically:

    // define redips_init variable
    var redips_init;
    
    // redips initialization
    redips_init = function () {
        // reference to the REDIPS.drag library
        var rd = REDIPS.drag;
        // define drop handler before DIV element is dropped
        rd.myhandler_dropped_before = function () {
            var my_shift_option;
            // JS logic to set shift option
            // define shift option
            my_shift_option = 'vertical1';
            // set shift option
            rd.shift_option = my_shift_option;
        };
    }
    
    // add onload event listener
    if (window.addEventListener) {
        window.addEventListener('load', redips_init, false);
    }
    else if (window.attachEvent) {
        window.attachEvent('onload', redips_init);
    }
    

    But if you mean to have horizontal and vertical “shift modes” at the same time, REDIPS.drag doesn’t have such option.

  5. Thank you for your immediate response… If I used myhandler_dropped_before drag doesn’t work. When I use like below coding drag will work but it will consider only one vertical2 shift option, please help me to work.

    var redips_init,
        shift_option;
    // redips initialization
    redips_init = function () {
    	// reference to the REDIPS.drag library
    	var	rd = REDIPS.drag;
    	// initialization
    	rd.init();
    	// set drop option to "shift"
    	rd.drop_option = 'shift';
    	// enable animation on shifted elements
    	rd.shift_option = 'horizontal2';
    	rd.shift_option = 'vertical2';
    };
    
  6. @prabu – REDIPS.drag.shift_option public property can contain the following values:

    horizontal1 – horizontal shift (element shift can affect more rows)
    horizontal2 – horizontal shift (each row is treated separately)
    vertical1 – vertical shift (element shift can affect more columns)
    vertical2 – vertical shift (each column is treated separately)

    Only one shift mode can be assigned, but shift_option can be dynamically changed in event listener (as I show in previous comment).

  7. Hi Darko,

    First of all big thanks for making all this available, it is really helping me learn javascript and build a prototype site!

    One question: While hovering an item (before dropping it) the cell underneath it is highlighted; is there a way to also highlight another cell with a relative position?

    The reason I’m asking is that some of the items in my page are the size of two cells and I want two cells to highlight while these items are hovering.

    let me know if this is possible!

  8. @Bartekko – Unfortunately REDIPS.drag can highlight only one table cell below dragged DIV element. To be more precise, only one cell below mouse pointer when DIV element is dragged.

    @Bakr – Thanks. I’m also preparing REDIPS.table lib to enable TD merge / split. In combination with REDIPS.drag it provides a lot of functionality (and it’s a fun to do).

  9. Hi~

    Can it possible work on quirks mode for IE8 or IE9?

    In quirks mode it seems no drag effect.

  10. @Alan Jhu – REDIPS.drag supports only standards-compliant mode, quirks mode is not supported. In quirks mode, each browser treats box model differently, so it’s impossible to calculate the same element offset in Chrome, FF, IE, Safari and Opera. “quirks” mode should be avoided because it is leftover which enables older HTML documents to still “work”.

  11. Hi,

    Thank you four your nice writing on Drag and Drop table content with JavaScript.

    Thanks.

  12. Newbie, so question is very simple.

    How can I dynamically change the “Hello World” in the example 0 into something else depending on the interaction with Apache?

  13. @Dave – Interaction with Apache (and maybe PHP) can be performed using AJAX. So, from JavaScript it’s possible to make a request to the server side, parse reply and display it anywhere on the HTML page (with DOM interaction). Please see my post AJAX progress bar where you will see how to create and use AJAX. After server finishes reply, it will be handled inside callback function on the client side (a browser). And finally, with a simple getElementById method, you can change Hello World of DIV element (DIV element should have set id attribute – unique on the page).

    // set reference to the DIV element (with id="a1")
    var div = document.getElementById('a1');
    // change "Hello World" to some text
    div.innerHTML = 'We Are Linux. Resistance Is Measured In Ohms.';
    

    Hope this answer will give you an idea of how to dynamically change elements on the page

  14. I realy love the JavaScript drag and drop. very usefull!! thanks!!!!!
    I do have one question: I’ve altered the code to fit my needs. I now have a table with 18 cells (6 by 3).
    I can drag divs to cells okay, but when I click inside the div the div will automatic move to the cell left of it.

    Has anyone had the same problem? What to do?

  15. @Albert – DIV element should not react on mouse click unless additional event listeners is attached to the element. Or the problem may be related to the styles. It’s possible that DIV element have been inherited some styles of parent elements in DOM. Try with simplifying – like deleting styles from CSS and HTML until problem disappears. If you will have any additional questions, be free to comment …

Leave a Comment