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 Darko , your advice was very useful. It was just what I wanted ! Best regards, Lubo

  2. @Jas – Please try to set example03 (AJAX version) where every drag-n-drop or delete is saved to database. If you have MySQL/PHP skills then preparing local Web server should be simple and easy. All instructions are written in readme.txt files.

    @Lubo – I’m glad that it fixed the problem.

    Cheers!

  3. OMG… Absolutely stellar library and examples. I have a request/question… I am trying to build a webpage where I have elements with an employees image, their name and title. How can I have all three elements in one single box that is draggable. When I try and build it, the image can be dragged separately, but I need the entire div treated as one element and draggable.

    Thanks in Advance!
    Cheers,
    JeffreyJ

  4. @JeffreyJ – All HTML code placed inside DIV should behave as one drag-able element. Please try to modify example01 and instead of:

    <div id="d8" class="redips-drag t1">
    <img id="smile_img" src="icon_smile.gif"/>
    </div>
    

    … place the following code:

    <div id="d8" class="redips-drag t1">
    <img id="smile_img" src="icon_smile.gif"/>
    <br/>
    Some text
    </div>
    

    Smile image and text written in the line below should move together.

  5. Excuse me. I have a problem.
    I what to drag images which i use bootstrap img-responsive on it.
    When I drag the image , it lose it responsive size and back to original size .
    i want to ask for how to solve this problem.

    Thanks .

  6. Hi, would like to check with you..

    For example 24
    1. Why the dragged item become “Error”?
    2. How can i add a col too?
    3. How to delete the dragged item if i accidentally drag something i dont want into the table?

    For example 1
    1. When i try to modified the table, i realize that the table 3 is a must, im trying to combine table 3 and 1, so the “Trash” button can go with table 1. but the program messed up and drag and drop does not works anymore. Is there anyway i can do so?

    Last but not least, you did mentioned this “initialize REDIPS.drag library: ” in your post.
    can i know where exactly this should be initialized? As i cannt find in your index.html code.

  7. Hi, is i possible to revert the performed drag operation after the backround ajax failed?

    Couldn’t find it in the docs.

  8. It’s possible to return “false” from event.droppedBefore() and in this case, dropped DIV element will be returned to source location.

    Cheers

  9. Hi! Great library! It’s really coming in handy for a class project. Question: Is there a way to tell which cell an element was dragged from? I know how to get the cell it was dragged to, but not the other way around. I read your documentation, but couldn’t find what I was looking for. Thanks!

  10. Hi Lindsey,
    in event.dropped() handler you can get all needed info from REDIPS.drag.td property – please look to the documentation or search examples for the “rd.td.source” in prepared examples.

    In short, rd.td contains reference to previous, source, current and target table cell.

    Cheers!

  11. I figured out the answer to my previous question! I found it in your documentation, and it works great. I have another question. Right now, when I drag and drop content, it snaps to a specific part of the cell. Is there a way that it can drop exactly where my mouse drops it instead of snapping?

  12. Dropped DIV element will be always placed to the cell bottom. Currently there is no way to set position of dropped element (DIV element is simply attached as child element to the TD).

  13. Hi,

    This new version is awesome.

    Few questions:
    1. We are using 4 columns in the table.
    The first column is the Label, second column is the Data (i.e. textbox, date, dropdown…etc). Same for the remaining 2 columns.

    Is it possible to allow dragging 2 columns together since they are in a pair?

    2. After completing the dragging, the JSON data for the positions will be generated.
    Is it possible to load these positions such that the ordering will change upon the page is loaded?

    Regards.

  14. Hi dbunic,

    I want to say thank you for your Redips library.

    I am facing one problem here, Drag and Drop not working both tables are not in the . But as per my requirement the left side table in one container and another one some other container. So please help me out if both table(s) are not inside to enable content dragging.

  15. @Chee Chong – It’s possible to move only one DIV element at the same time. However, please look at the example12 or example17 (this one is a bit complicated) how to move more than one DIV element.

    saveContent() method can generate output in “classic” query string format or in JSON format – both formats contains and location (row / column) of DIV elements. So, if this location is saved to the server it should be preserved on page loading as well – it depends on page logic to correctly render HTML. Other approach is to use loadContent() method (in onLoad event) to display table content.

    @Prasanna – To allow dragging DIV elements between tables, all tables should be placed in the same container. To start debugging, please make your dragging container visible with the following CSS style:

    #redips-drag {
        border: 1px solid lime;
    }
    

    This will help you to see dragging container and to verify if all tables are correctly placed inside container.

  16. is there a way of not losing the data once the page is refreshed. for example storing the user timetable so if he closes and reopens it all the data is there from last time. I’m new to programming sorry.

  17. Ada,
    REDIPS.drag is a front-end library for dragging DIV elements inside HTML table. To save table content, it’s needed to call some sort of server side script. Script should accept table content and insert to database. To start with such scenario, it’s best to look example03 “School timetable” and apply modification. Example03 requires local Apache/PHP and MySQL database.

    Table content can be restored on the server side (like it’s done in example03) or with using REDIPS.drag.loadContent() method in example28.

    Cheers!

  18. Would be great to add ‘ target=”_blank” ‘ to the link in the corner or also to links in the main table :))

  19. Hi, thanks for the library. It’s very useful.
    I have a problem when tables are larger than screen width. When the table is larger than the screen height there is no problem, you can scroll down and drop the div anywhere without problems but when I have to do horizontal scroll the div seems to not recognize that it is in a new column and it returns to its original position or to the nearest position to the right side of the screen (before make de scroll). I have also used the changed evento to show the position while the div changes and when the div arrives to the border of the screen and I scroll horizontally the changed event stops responding.
    Is ther any way to solve this issue.
    Thanks in advance. (and sorry for my poor english).

  20. Rafa,
    your problem might be related to the dragging container. To start debugging, please make your dragging container visible with the following CSS style:

    #redips-drag {
        border: 1px solid lime;
    }
    

    This will help you to see dragging container and to verify if all tables are correctly placed inside container.

Leave a Comment