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. hi, great code!. I need table1 and table2 at left and right, not up and down, so I use a third table. However, the “drop” only works for the “container” table cells. How can I solve it?. Thanks!!!

  2. This looks fantastic but i was wondering if you guys could give me a hand with some code please?

    I have a sql database table that has a list of insurer schemes that have 1 or 0 in another column whether they are are on or off.

    I want to be able to display schemes in one column if they are on and another if they are off and then update the sql table if they are moved from one column to the other.

    Is this possible?

    If so could someone post some example code to get me going?

    Appreciate your help on this guys!!!

  3. Is there a way to make it so if you drop an item into a cell that’s already taken, it will take what’s in the occupied cell, and switch it into the space where the object you’re dropping into the occupied cell originally was?
    i.e. make two items switch places

  4. Thank you. Very impressive. 1 question, is posible to implement this feature into a category vs product form functionality? Let’s say, I have product1, product2, product3 in a tableProduct, and 2 more tables, tableCategoryA and tableCategoryB, after dragging and dropping, is any way to detect the where are the objects and save it in a DB process?

  5. Hi!

    This .js is fabulous!
    I’ve a very big question and also need a help. How can I drop content into a textarea?
    Is it possible with your js?

    Thank you in advance!

  6. @andres – place your tables in DIVs within main DIV container. With tables in DIVs, you can set float style and arrange them to stay side by side.

    @SCB – If you saved table content, then you should use server side engine (PHP, ASP, JSP …) to create new table HTML code.

    @Jason – That shouldn’t be so hard to implement. When user begins to move table cell, source location is remembered. On the other hand, when left mouse button is released, we know destination cell. So, if destination cell has some content, it should be placed to the source location. I will try to add your idea to the next release. Thank you.

    @10Gkun – Please see the code executed on button click “Click” (button below tables). This JavaScript code scans first table and displays order of table content. You will only have to send this information to the server and save it to the database.

    @Laszlo – Huh, it wouldn’t be impossible, but my code has no such option. When left mouse button is released, dragged object is placed to the destination cell. In case with textarea, you will have to read text from the dragged object and add it to the bottom of the textarea content. With few customizations, this code can be arranged for this specific need.

  7. Veryyy great script!!!

    It’s possible to switch 2 DIV? If I take one div, and if I go over another DIV, that swicth the 2 DIV, I never see that, I don’t know if it’s possible…?

    Thanks ;)

  8. Ok, sorry, I have read jason post, he want the same idee than me, it’s hard but possible :) (and sorry for my english)

  9. Where do I restrict no two or more contents (Draggable items) should not be placed in one cell.
    And one more…
    I want from one row one cell can move only to the specific cell and specific row. Note I want to restrict both (cell as well as row)

  10. How do I save previous cell and row value?
    Because it is retested on calling set_tcr() each time…
    No way to save … how to save?
    Means I want both the current as well as previous cell value same time

  11. @SCB – With property single_content = true (at the top of the drag.js), you can define single content per table cell. When user click on table content, variables table_source, row_source and cell_source are set. This way, in moment when user release left mouse button, you have information of started position. This is mostly used in case to return content if user cancels delete confirmation.

    Unfortunately, script now hasn’t option to define possible destinations for each table cell content.

  12. Hello
    I work with netbeans 6.5, I would like to use your code in some project, but it don’t run. Can you help me?

  13. Hi,

    Thanks a lot for this script!

    I’ve notice than when I submit the form, it sends the old value of the text boxes, instead of the new value I may have written in them. Has it anything to do with the script, or I’m doing anything wrong?

    Thanks, and excuse my english,

  14. Hello, excuse me for my last question.

    I’ve studied it and seen that the bug was mine: In the fucnction table_content() I’d inserted a line tah says:
    tbl.rows[r].cells[c].innerHTML=tbl.rows[r].cells[c].innerHTML.replace(/sacd/gi,r+’-‘+c+’-‘+’sacd’);

    The word “sacd” is a keyword include in the field name in order to make this replacement.

    I made this because I need to include the row and col values in the name of the field to be posted. But now, I have that problem. Could you tell me how could I do it?

    Thank you very much,
    Rafael

  15. Does any one have a solution for Jason’s idea. I am urgently in need of it. Couldn’t figure out how to do it!!:S

Leave a Comment