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 it possible to store the location of div’s as they are moved so when I reload the page there in the order as I left them?

  2. What an incredible script!! Thanks for the effort. I have this question, the dragging didn’t seem to be working when I dynamically create a table inside tags. Do I have to make any changes the JS?

    Ravi

  3. @Tulup, @newB – Handlers for clicked, moved, not moved, dropped, switched, cloned, deleted and undeleted are created. Messaging from handlers are directed to the table cell “Table3”. Hope this will do the job ;)

    @Colin – You will have to save the order of elements to the server – I suppose to the database. In “table_content” function you will see how to collect order of DIV elements in table. After DIV order is saved to the server, instead of static index.html, you can create PHP, ASPX, JSP … page and generate DIV elements in table cells.

    @Ravi – If you want to enable drag-n-drop for dynamically created elements, you will have to set class name to “drag” and attach onmousedown event. Please look to the window.onload anonymous function for details.

  4. Is it possible that when dragging Box B on top of Box A that B would take A’s place and A would just move over to the next cell on the right? Instead of swapping the two locations?

  5. @dbunic – thank you :)

    @Colin, @newB – now you can AJAX the new order of DIVs to the server and to remember and visualize their last state. I will provide examples soon

  6. Hi,

    After dragging DIV, the width of the column is getting shrinked.

    Is there anywhere the width of the table has been set.

    I dont want the column width to get shrinked.

  7. Hi dbunic,
    You’re doing some great work here. Thank you for that. I’m using your script in ASP web application. I have to work with IE and I think I found a bug in IE 7 (in IE 8 looks fine).
    I show you screens.
    I put couple of divs in one cell:
    http://img34.imageshack.us/i/31580362.jpg/
    and then movend one by one to the cells on the right in the same row.
    http://img7.imageshack.us/i/18981049.jpg/
    When height is changing the divs dont move upper.
    Sorry for my english :)

  8. I’m playing with this script but I’m not a programmer. I’m trying to create a list of “clone” items on the left that the user can choose from to create a few custom lists within the table. There appears to be a bug with Clone items if you do not move the cloned item off the parent cell completely. Start by grabbing a clone item and start moving it to another cell. Before you completely leave the parent cell, try letting the cloned item go. It will place itself below the parent item in the same cell even if the “single” switch is enabled in the .js file. Is there a way to lock the parent cell so that it is invalid to drop anything on to it during the cloning process? Class=”forbid” will not work. It causes crazy stuff to happen.

  9. Hi dbunic, thanks for the excellent script. Question: if the (cloned) div is dragged from the (class=’clone’ cell to a point outside of (source_table or destination_table, or even div id=’drag’) could the div be removed, or perhaps have its destination cell predefined for errant drops?

    example:

    ondrop:
    oParent = obj.parentNode; //parent == document(?)
    oParent.removeChild(obj);

    or

    if (!table){tables[table].rows[row].cells[cell] = document.getElementById(‘trash’);}

    thank you.

  10. Hi dbunic, thanks for the excellent work by you and the feedback as soon as I asked for help..(swapping the content of the divs). With your help, I have successfully implemented a small timetabling program for a small school. I used your drag and drop script, with some modification, to allocate the subjects that were not allocated automatically by my algorithm. It works fine now..:) thanks again…wonderful work by you…

  11. leslie says:
    “Is it possible that when dragging Box B on top of Box A that B would take A’s place and A would just move over to the next cell on the right? Instead of swapping the two locations?”

    Same question from me, project will be full, if i will can define in options, that if some element will be moved to cell where other element already is stored, then old content will be move to the next cell on right, and if needed move all another right-hand cells content to next cells. If this options will be ON, and table will be full, and user will try to push just one more element to full table, the error alert will be produced.

    Thats all, Please Code this and i will be beholden, to You ;)

  12. How about draging and dropping images instead of divs? I tried by putting on cell an image, instead of text, but it does not drag the image down, it drops on the cell that you release the mouse but as I said the imnges is not being dragged.

    Even I tried to use img tag instead of div on the drag.js, still no luck.

    Any help or idea?

    Thanks,
    Ilir

  13. @leslie, @Name – Nice idea. So, you want to shift existing table content from the dropped position to the last table cell. If the last cell is occupied, then table content can’t be shifted (because content from the last table will drop out of the table). Sounds challenging … I hope this “shifting” will be in the next release.

    @SCB – You can set DIV with as well as TD with. In my example, DIV with is set in style.css, while TD (column) with is set in HTML with colgroup.

    @Damian – I fixed script (two more lines) and there shouldn’t be any problem with elements positions and changing TD height. IE6 / IE7 are forced to redraw UI after element dropping. The trick was: element.className = element.className

    @shinyranger – You are right. I fixed script, and now you can’t drop cloned element to the same cell with source. If you try, then cloned element will be deleted and myhandler_notcloned() will be called.

    @Michael Miller – OK, I will try to add option to remove cloned element if cloned element was dropped outside of the table.

    @newB – I’m glad my script helped you :) … Cheers!

    @Ilir – Did you try to place image in the DIV with class=”drag”? I’m not 100% sure, but you should be able to write any HTML in DIV.

  14. Hi dbunic,
    thanks for fixing the script. It works perfect.
    Nice trick you use :)

  15. Great script, thanks for keeping up and continuity of improvments made.

    I would like to use this technique in case when the cells are not text, but links as below:

    However when I test the above I am getting the following inconsistent beaviour between two major broweser, IE and Firefox.

    1) Dragging and dropping
    IE – the link image does not move from the boundaries of the cell,and while you move the image it is not visible during the move, it stays on the original cell though until release of the mouse, however it gets dropped in the destination cell. The “<a href.." tag does not get executed, and that is fine because my intention were to drag and drop only.

    Firefox – works well, the image get dragged, it is visible during the process of move and dropped nicely on the destination cell. The issue is, when I release the mose the "<a href .." tag gets executed, meaning I am getting away from the page of drag and drop, while my intention were only to drag and drop and not to click on the link.

    2) Clicking on the links (not drag and drop)
    IE, the "<a href .." does not get executed at all, in this case the intention is to click on the link.
    Firefox, the "<a href .." get executed fine, and that is correct.

    3) Drag and drop on the forbid cells.
    Please try that: drag a cell "A" and try to drop it on a forbid cell, if on the way of move there is another cell "B" that you mouse-it-over while dragging, then the drop happen on cell "B", while no drop should had happen, the destination cell was a forbid cell not "B".

    I would appreciate if somemone might offer any kind of help.

    Thanks,
    Ilir

  16. Hello, for any change, would it be possible to select more than one cell (by ctrl click for example) and dragging multiple cells at once? It would only be possible to select cells from the same column and next to each other.
    This would be a killer functionality! Thank you!

  17. Hi

    I have placed two div’s in one td. this is achieved by Single_content=false.

    But how to save two div’s under one td.

    is it that it should be saved in Data base?

Leave a Comment