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,196 thoughts on “Drag and Drop table content with JavaScript”

  1. I implemented switch table content as you asked. Instead of single_content property, you will find drop_option at the top of the drag.js script. In this demo, values (multiple, single and switch) of drop_option property are changed with radio buttons below tables.

    Happy dragging!

  2. Wowwww wonderfulll!!!!

    But :$ Can we switch only 2 div, not all the table content?

    I look the source, but for the moment, we can swith 2 table content, ok, but me, I would like switch just 2 div, not all the table content, but i think my request is hard lol

    Thanks

  3. Thank you dbunic! it works perfectly, just one question. When you have either a new [td] or a new [table], as you drag the upper level to a lower level, it puts the image, or text, or button, whatever you have inside the cell, underneath the lower one you’re dragging it to, is there any way to always keep the image that you’re dragging looking like it’s “above” the one you’re dragging it over?

  4. Another bug I found, I think if you have the “switch” on, then it lets you stack more than one ontop of the other, but the only way I could reproduce this bug is if I did switched them extremely quickly, almost randomly clicking and throwing the content into another cell

  5. @Jason – Now dragged DIV should always be above the other DIV elements. This was due to z-index (zIndex in JavaScript) CSS property. And about bug you found … Did it happen here, I mean in demo included in this page? Can you repeat this bug if you unpack redips2.tar.gz and load it locally? I noticed that demo becomes slower as content of this page grows, so this could be the reason because fired events can’t be processed quickly as needed. I think the key may be in limiting event bubbling / propagation, but I’m not sure …

    @Jindo – Yes, lock/unlock can be useful. Thank you Jindo.

  6. hi, dbunic, I have a with all the cells filled with divs. I want to switch the divs positions once they are dragged and dropped to another cell. Its the same question Jason asked some time ago. Can you make it to happen pls?

  7. Is it possible for this to work without using tables? For example, I’d like to have 8 images that are just floated to the left. I’ve tried putting “class=drag” on the image tag but this doesn’t seem to work. Any suggestions appreciated. This code is perfect otherwise!

  8. @leslie – This script is designed to work with tables and can’t work without table cells. HTML table gives you raster where you can land dragged object.

    @Jindo – Yes it is, instead of running whole “onload” tasks, you have only to set onmousedown event for the new DIV. I think that should work. Anyway, please see how onmousedown event is attached to every DIV element inside “drag” table. BTW, nice page and I can see “lock” functionality as you mentioned before. Thanks!

  9. Oh nope, I got it all fixed, thanks a lot dbunic! I forgot to link the CSS to the page haha, stupid mistake

    I’m using the script on my browser based RPG, it’s more text based than anything, but for the spell system, I’m allowing the users to drag the current spells they know down into an 8 cell wide bar, while on top of that is a list of all of the spells they know. I made it so it remembers the order that they put the spells in and everything, but I wouldn’t have been able to do any of this without your script though, thank you so much!

  10. Is it possible for me to make an ajax call once a div is dragged and dropped or when I try to drop??

  11. Hi, Jindo and me like your work very much. We (and newB …) have small request: is it possible to have different handlers? For example – moved, switched, cloned, deleted handlers. Greets and thank you!

  12. Great script!!! Really nice.

    Just one question. When I have a number of DIV’s in a cell and want to change the order between them (or add a new oine), the one I am dragging always comes to the bottom of the cell. Is there anyway to arrange the order between them by drag-n-drop?

  13. @Jason – I’m glad it works … :)

    @Tulup, @newB – OK, I will create handlers (actually empty JS functions) so you will be able to place your code inside …

    @Roland – I’m sorry, but script recognize table cells only. Currently you can only place dragged DIV to another cell, but you can’t arrange order of DIVS inside the same table cell.

Leave a Comment