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. JS code is optimized (number of calling set_trc and getScrollPosition is reduced) …

    @Senthil – I’m thinking to implement climit_X directive (actually this will be classname with X as integer) to define clone limit with two options for the last clone element. In the first option, last clone element will stay in the cell (like you asked – without moving and cloning) or last clone element will become only movable (no more cloning). So, this add-on will solve your problem and can be useful in general.

    Single option means to forbid landing to already occupied cells. In other words, element can be dropped to the empty cells only.

  2. Very cool Mr. Redips. I like it!

    I’m teaching myself JavaScript and found your site looking for drag and drop samples that will help me with Internet Explorer 6. Unfortunately, even your example doesn’t work in my IE6. I have some “cross-browser” code from JavaScript the Definitive Guide by David Flanagan [http://docstore.mik.ua/orelly/webprog/jscript/ch19_03.htm] that doesn’t work either. I’ll keep on looking and let you know if I find one that works.

    BTW, do you work with JavaScript on a commercial basis or just for fun?

    Kind Regards,
    Michael Alexander

  3. @Senthil – “Drag and drop” code has new cloning features. Now it’s possible to limit number of cloned elements. Just add climit1_X or climit2_X class names where X defines number of cloned elements. With climit1, “clone” element will become ordinary movable element after last element was cloned. With climit2, clone element will “die” (no more cloning, no dragging) after last element was cloned.

    @Michael – After every upgrade, I test JS code with IETester and dragging works in IE6 emulator. Unfortunately, I haven’t clean WinXP installation with IE6 near to confirm compatibility problems that you mention.

    I work as WEB developer, mostly on intranet WEB aplications so all posts/examples on my site are highlights from decade of creating WEB applications. In the meantime, I reached a state of mind where JavaScript is my full time job and fun in the same time. ;)

    Anyway, it’s nice to know my script was useful for you.
    Cheers!

  4. Hey,

    Your script is perfect! Integration with existing HTML was a snap!

    I’m having two problems though. First is it possible to have multiple drag div’s? Because their ID’s are the same, spanning across multiple tables doesn’t work, unless I encapsulate them all into one huge div.

    If that isn’t possible, how about a reverse of the forbid class? Like include (rather than exclude)? The existing pages already contain tons of tables, divs and the like. Adding class=’forbid’ to them isn’t an option.

    Lastly is it possible to only allow items to be dragged into empty cells rather than having to use getElementById(x).removeAttribute(‘class’); to manually remove the assigned class?

    Hope to hear from you soon…

  5. @Kevin – Multiple drag isn’t supported. It’s possible to drag only one DIV element at time. Script is updated and instead of “forbid” class name, now cells are marked with class name “mark” (you have mark_cname option to change default setting). With marked_cell option you can define allow or deny behavior for marked cells. In your case to allow dropping to some table cells, you will have to mark table cells and set marked_cell=’allow’

    To allow dropping objects only to empty cells, please set drop_option=’single’ (if I understood your question).

  6. Terrific bit of work! There is a lot of utility in this script. Curiously, when I execute it under my WAMP the multiple parameters always reports…

    “Accepted parameters:
    “; } ?>

  7. i have a quick question about the div id of the cloned object. do you know how to append the new object id with the id of the cloned.

    i would like something like:

    obj_new.id = ‘c’ +cloned_id+’_’+obj_old.id

    unfortunately i don’t know how to do this any help would be much appreciated.

    thanks,
    eric

  8. Again, thank you for all of the work you have put into drag.js.

    And, thanks for using jsLint – !

    Kind Regards,

    Mike Miller

  9. @Nikkie – Yes, the problem was in short open tags. I used <? instead of <?php in multiple-parameters.php

    Please try to modify multiple-parameters.php or enable short open tags in WAMP configuration. If you are unsure, try with newer redips2.tar.gz package – it should work now.

    @eric – If I understood, the question is how to append ID of clone element to the ID of cloned element? In some way to allow tracking the origin – who is parent of cloned element? Script is slightly modified. The ID of clone element is attached to the new ID. IDs are separated with “:” because “_” is already used to compound id, table, row and column parameters.

    Modified line 770 in drag.js now looks:
    obj_new.id = ‘c’ + cloned_id + ‘:’ + obj.id;

    @Michael – drag.js becomes better thanks to your suggestions – thank you! Anyway, JSLint was a hard nut to crack. Oh how I was happy after JSLint said “No problems found in drag.js” ;)

  10. Hello dbunic,
    First I love your code, thx.
    I found a problem with firefox. If you create a table with a row containing more than 6 cells, it will not allow to drop in the cells on the far right. It works fine with IE.
    If somebody hit this problem let me know.

  11. Correction about my previous post. It is not because of the number of cells, but because of dropping on the right side of the document, possibly behind the right margin. I decreased the size of the drag element so the whole table fit, and it fixed the problem.

  12. Hi

    Where are you add space when u put a div?

    My requirement is:
    When i drag and drop, the items should move up and then give space to add the new div. At present after drop only it gives space. I dont want that. While my cursor moves to that TD to drop the div i want the other divs to move up and give space.

    Is it possible?

  13. can you modify the code — please please

    to copy or MOVE the whole column (vertical ones) to another table

    many thanks

  14. it’s a very hard work thanks so much.
    i want to learn if i can omit the resizing of the cells after inserting new clonable elements inside of it.

    thanks a lot

  15. also i’ve one more question:
    can i’ve bigger clonnable objects which is in more than one cells?

    i want to use this script in my graduation project so i need the answers of these questions. or can you advise me some book or other things to learn js?

  16. resizing is not a solution since i’ve to 10*6 table after and 1*6 table and spaces between tables.

    the other soln may be usefull i’ll try it.

    thank a lot

  17. @SCB – After mouse button is released, dragged DIV is moved from his parent node to the selected table cell. Actually, DIV is appended to the end of the list of children of a specified table cell. And that implies automatic space adding. Simply said, after mouse button is released, appendChild makes the magic happen. ;) I’m sorry, but modifying code to show the space before releasing button isn’t easy and it will be considered later if I catch more time. Thanks for your understanding.

    @3xxx – Currently, I’m working on new – drag and drop table rows – code. It’s in primitive phase, and I need more time to finish first version. Dragging columns will come to my schedule after dragging rows will be finished … Sorry, but I’m only a one man band ;)

    @deniz – I suppose you can omit resizing table cells if your table cells are bigger than dragged element. Try to increase width / height of table cells in CSS. You can define size of clone element as you like. Every element (and clone element also) should fit in one table cell. But table cells can be row / column spanned, so it can look like one element is placed in two cells – if I’ve understood your question properly.

  18. Hi,

    Very nice indeed! I’m planning to use this for some experiments where sentences need to be annotated. A table would be built with one column per word and a drop-down with labels can be dropped under every word. Also another cell for free text (comments) can be used. When I process the results, how can I then retrieve the contents of the dropdown and the text cell ? multiple-parameters.php only gives me the positions of every cell.

    Miguel

  19. @Mpho – source of drag.js is zipped in redips2.tar.gz package. Demo uses jsmin version of drag.js included in WordPress post.

    @Miguel – If your text cells are <input type=”text” … then you can wrap dragging table in <form></form> and instead of calling save_content() and multiple-parameters.php you can simply submit form.

Leave a Comment