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. Hi,
    I’m having trouble using this library when the div with id=”drag” is scrollable. When dragging a draggable element that was not visible when the page was opened, it will not drop where I expect it to. It doesn’t seem to recognize the non visible element as able to drop onto. I made a simple page to reproduce this behaviour here
    Any help will be appreciated.

    Marc

  2. @Marc – I will send you modification of your tablescrolltest.html example. I made a little correction of styles and replaced drag DIV with content DIV and vice versa. You will see also two elements in the right column with:

    1) visibility: hidden
    hides the element, but it still takes up space in the layout.
    
    2) display: none
    removes element completely from the document (it does not take up any space)
    

    I tested example with Chrome, Safari and IE8 and autoscroll works as expected. If you will any other question, don’t hesitate to ask.
    Cheers!

  3. I’m getting some weird formatting results. When I view it from the computer where the site is stored, I get the result I want. But from anywhere else, the dragable items do not look correct at all.

    Try this to see what I want.

    Going to the site will show you what I get.

  4. I love what you’re doing here. I’ve been using a jQuery plugin called datatables (http://datatables.net/) and I’m curious how difficult you think an integration would be. I spent about 30 min playing with your code, but I couldn’t tell how tough it was going to be. Thanks for any insight.

  5. Hi again,

    I must have been doing something wrong before because on my second attempt it was quite simple to get your drag and drop class to work nicely with datatables.net.

    Thanks for the great work.

  6. @Chris Joy – It’s really weird you have different style results for page viewing from local and remote computer. As I can see, your default.css is mentioned outside of the head section. Please see documentation of Link element on W3C site. It says: Link element may only appear in the HEAD section of a document. Well, this may cause mentioned problems. On the other hand, you can define styles for drag class name so dragged element will not have inherited styles / strange behaviour.

    @Jesse LaVere – I’m very glad that REDIPS.drag and jQuery plugin can work together. Thank you for feedback info.

  7. Great tool. I’m really enjoying it. I was wondering if you could show me how to allow cells to be dragged to other cells on the same row, but not on other rows?

  8. @Jesse LaVere – Here is JS code you asked. In case of dropping element to any other row/table, element will be returned to the source position. It’s only allowed to drop elements within the same row. Code can be even simpler if there will be only one HTML table on the page.

    rd.myhandler_dropped_before = function () {
        // get target and source position (method returns positions as array)
        var pos = rd.get_position(),
            tbl2 = pos[0],    // table index (target)
            row2 = pos[1],    // row index (target)
            tbl1 = pos[3],    // table index (source)
            row1 = pos[4];    // row index (source)
        // if target table/row differs from source table/row then return false
        // element drop will be canceled and returned to the source position
        if (tbl2 !== tbl1 || row2 !== row1) {
            return false;
        }
    };
    
  9. @Mufler
    You should view the example without a direct link with the database ;) (that there is a full example for testing with a db)

  10. This is an excelent tool. But I need to serialize the table at any time in order to update the changes in database. So my question would be, what’s the best way to get the data re-organized in a JSP and serialize it to a struts action for example. Thanks in advance.

  11. @Rub3s – You took the words right out of my mouth. Thanks! :)

    @Sérgio Teixeira – You can send table content to the server side in two formats: as plain query string or in JSON format. Please see documentation for save_contet() method. Method returns table content as query string or in JSON format. In this example, table content is saved on user action. When user clicks on the Save (Save1 or Save2) button whole table content is sent to the server at once. On the other hand, you can send information to the server side on every element drop. This way saving to the database can be realized one by one DIV element. Here is code snippet from example03/ajax/script.js file (all sources can be found in redips2.tar.gz package):

    // save - after element is dropped
    rd.myhandler_dropped = function () {
        // get element position
        var pos = rd.get_position();
        // save table content
        send_request('ajax/db_save.php?p=' + rd.obj.id + '_' + pos.join('_'));
    };
    

    I hope this answers your questions, but if not, please reply and I’ll try again.
    Cheers!

  12. Hello,
    I have difficult time in getting some calculations done based on row drop from one table to another. My sample is in sample. All I need to achieve is when I drop a row from top table to bottom table row, I have to add, for example, Number of Bundles from source to target. As I have no basic jQuery knowledge I’m struggling with this for few days. Could you please help me?
    Thanks.

  13. I have problems when page width is bigger then screen size. Drag is not working. How could I fix that?

  14. @Murugan – REDIPS.drag library is encapsulated and can work with any JavaScript framework (such as jQuery) or it can stand alone. Means, REDIPS.drag is not jQuery plugin. Sorry, my jQuery knowledge is not on high level. Anyway, you have prepared nice example and someone will help you for sure – please jQuery guys …

    @Nurlan – Maybe the problem is due to DIV#drag dimensions. Please add the following style to the style.css file:

    #drag {
        border: 1px solid lime;
    }
    

    This will make DIV#drag visible. So if DIV#drag is smaller than table, then some columns may not work. Just set correct width to the drag region and dragging should work fine. This problem is mentioned in new post Appendix A.

  15. Hi,
    I have a problem if use jQuery and this java script on same page drag and drop not working. Can give solution for this problem.

  16. @prabu – Probably is something in collision. REDIPS.drag should work with any JavaScript framework. Anyway, it’s hard to make a diagnose on a short descrption so if you have online example I will try to look and see where is the problem.
    Cheers!

  17. Thanks for your response.

    The problem is because of i call your code from one separate page to main page using jquery ajax call..
    When the page(contains your script) called from ajax function means the drag and drop options not working.

    Its working fine If i use your script in the same page without use of any jquery ajax call.

    So please help me to work your script in the jquery ajax call!

  18. @prabu – redips-drag-min.js file should be loaded and REDIPS.drag.init() called to enable drag-n-drop. The best way is to run initialization inside window.onload event handler. Maybe in your case, you only need to call initialization of REDIPS.drag lib in AJAX callback function. rd.init() can be called many times so there should not be a problem.

Leave a Comment