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 restrict the drag drop of a particular cell within the row it is part off??

  2. This is what I use to keep a DIV in its own table, you can use the additional data returned from getPosition() to limit to a row in the same table

    rd.event.droppedBefore = function () {
        // Get TO location
        var loc = rd.getPosition();
        // If this is not the same table the CELL came from cancel
        if (loc[0] != loc[3]) {
            return false;
        }
    };
    
  3. All dropping rules can be accomplished similar to the Kevin’s simple example. You will only need to prepare some JS logic inside droppedBefore() event handler. getPosition() method returns array with target and source DIV position (please see documentation for more info).

    Kevin, thank you very much for helping.

  4. many thanks to the wonderful tools.
    but i encounter a problem that i’m making a single page app, and the drag table is generated, and when in other dropMode, it’s ok. but when set to ‘shift’, i got an err “Uncaught TypeError: Cannot read property ‘cells’ of undefined” in line 3763. one more thing, when i tryed save the page, and visit from local, everything is fine.

    I do run the init() method after generated all elements.

    so, any tips to help me get through the problem? many thanks!

  5. help
    I tried to put this ajax trigger:

    $.ajax({
        type: 'POST',
        url: 'set_order.php',
        data: 'positions=' + source.rowIndex + ';' + pos[1],
        success: function (data) {
            //finished
        }
    });
    

    in the rd.event.rowDropped event but the ajax is not triggered… any clue to help ?
    thx
    FF

  6. @michael – I’ll not exclude a possible bug and this problem might be related to missing TD properties needed for REDIPS.drag library. For some deeper inspecting I’ll need a prepared example – like link to your page or JSFiddle. Here is link to existing REDIPS.drag example that can be reused for your demo:

    http://jsfiddle.net/dbunic/cexn1wvn/

    @fred – First you have to confirm that event is triggered at all. Place the following JS code to the event handler:

    var el = document.getElementById('myMessage');
    el.innerHTML = 'Event triggered';
    

    … and you’ll need to place “span” HTML tag the page:

    <span id="myMessage">Test</span>
    

    If “span” message is changed then event is invoked and the problem is somewhere else.

  7. Is it possible to prevent any changes to the div positions if the user drags it to somewhere that is not a table cell? It would be useful if a user, upon finding out that he/she doesn’t want to move the div and has forgotten where it was originally, wanted to put it back.

  8. I am sorry but I don’t get how to keep a cell in its own table. How should I use Kevin’s script? Thank you in advance. Great Documentation I hope to be able to learn more.

  9. @shao – Dragged DIV can be placed only to TABLES (table cells) that are inside “drag” containers. Anyway, if needed, it’s possible to mark source cell (set another color) and set it back after DIV element is dropped. Please take a look to the event.moved() and event.dropped() documentation. In both events you have reference to the source cell (rd.source) and you only need to set background color …

    @John – Actually it’s not “cell” staying inside table but it is DIV element. So, when user drags around DIV element and in a moment when DIV element is dropped to the table, event.droppedBefore() will be triggered. If “false” is returned from event handler, DIV element will be placed to the source cell.

  10. Great tool!! I just have discovered it this morning… and already up and running for my project! Simply awesome!

  11. Hi dbunic,

    I’m building a prototype study plan and wanted to reduce the use of tables, I have limited the tables to the drag areas but noticed the div id=drag is interrupted by other div elements (with an id) outside of tables.

    Is it possible to ignore these id’s? I am using them for js but I want the tables as one container.

    Thanks!

  12. @RomanK – I’m glad you found REDIPS.drag useful for your project. Cheers!

    @Pat Harding – REDIPS.drag library needs to have defined drag container (DIV element with id=”drag”). This is important because only this region will be scanned (instead of whole page) for TABLE/TD and changes that might happen. Element id on page should be unique (as its name suggests -> id – identifier), but browser will not complain if page contains several elements with the same id (to be honest, more elements with the same id is not by the DOM specification).

    In short, DIV id=”drag” defines drag container and it’s needed for REDIPS.drag library.

  13. Hi dbunic,

    Its been a while working on with the drag and drop feature. I have a question for you. User specifies the starting and ending position in the table, all the td contents have to move in between those specifications. Is there any i could solve this problem.

    Earlier i worked with the moveObject() function and move all the stuff on the client side but right now i would take the request from the user and need to move these data.

    Once again thanks for your time and help.

  14. Hi
    I would like to clone fields cover one table field, fields covering two fields.
    How would you do this in a the most simple way?

    thx
    Phil

  15. Hi dbunic.
    First of all I want to say “thank you” for your library. It is very useful!
    I have a question that is difficult to explain with my poor english.
    I have two tables, one hovers the other. The biggest one is greater than the viewport (and I have to scroll it to see certain cells). When the viewport is NOT positioned at the left-top of it and I want to drag a DIV from the small table (that hovers the big one with CSS = position:absolute) to the big one, the big one starts to scroll automatically. This is a problem for me.
    It doesn’t happen when then viewport is located at the left-top of the big table.

    Thank you in advance.

    Paolo

  16. Hi everyone!

    Is there any way I can adapt this drag and drop to work on lists instead of tables?

    thanks…

  17. Your Drag n Drop example #10 Sticky tables looks like the best solution for a project that I have where the site visitor has to choose 12 images from individual catalogs (as per the scrolling containers on the left) and drag each to a specific position to a receptacle (as per the static container on the right).

    One of my challenges is how will I integrate the form with a shopping cart purchase. Should the purchase be made first and them the customer makes their drag n drop selection -or- should they make their drop selections and then go to cart… and suggestions?

    Also, once the selections have been dropped, the receptacle has to emailed for confirmation.

    Any advice would be greatly appreciated.

  18. I’m using pretty large tables representing cabinets in which I drag’n drop equipments. It works pretty well and your library is terrific.
    All my cabinets are tables and inside a div. In order to ave a better visibility, I can change the zoom style of my div from 1 down to 0.5. For example if you change in your example1 it becomes very difficult to drop under the mouse.
    Any suggestions?

  19. I’m using pretty large tables representing cabinets in which I drag’n drop equipments. It works pretty well and your library is terrific.
    All my cabinets are tables and inside a div. In order to ave a better visibility, I can change the zoom style of my div from 1 down to 0.5. For example if you change your example1 adding to your div style=”zoom:0.8;” it becomes very difficult to drop under the mouse.
    Any suggestions?

Leave a Comment