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. @Alex – Id of cloned DIV element will be changed in a moment of cloning. If id of original element is “test1” then first cloned DIV element will have “test1c0”, second cloned DIV element will have id “test1c1” …

    So, the solution for your problem to define separate class name:

    .mystyle {background-color: yellow;}
    

    and to use it in class attribute

    <div id="test1" class="drag clone mystyle">Hi</div>
    

    @AbdelHamid – example23 is updated and there is no longer need to define code_length property. New version has small regex to extract original id from cloned DIV element. Just download latest package (version 4.6.18) and try – now it should work no matter of the id length …

    @Chris – REDIPS.drag is a frontend JS framework and has no influence on SQL structure. After parameters are send to the server and accepted in PHP, ASPX, JSP or any other technology you can construct insert statement for any database. As I primarily work with PHP all demos shows how to accept location and DIV id with PHP. Code is well commented and there should not be a problem to rewrite it to any other script. Please see source of example01, example03, example22 and example23 to see how to save DIV id/position to the database. All examples are listed on preview page.

    @Krishna – If dimensions of input fields are changed in a moment of dropping DIV element to the table cell then the reason might be in style inheritance. With DOM inspector please try to find out which style is causing the problem. Chrome, FireBug and other DOM inspectors have a nice option to turn on/off styles for selected element on the page …

    @Juan Carniglia – I didn’t play with combining resizable from jQuery and REDIPS.drag but generally speaking, REDIPS.drag should work with jQuery. In example00/index2.html you will see a small demo where additional table is loaded using jQuery AJAX. After table is dynamically added to the page, DIV element can be dragged to the new table. On the other hand, rowspan/colspan attributes of TD cells can be dynamically changed and drag-n-drop will still work. I hope my comment answers your question, if not, don’t hesitate to ask again …

    @barry – Each table should be closed within its own drag container. Please see example17 – Move object (animation). This example copies each move to the other table – it’s irrelevant for your case – but HTML can give you the answer. This way DIV drag and ROW drag will stay closed for each table.

    In case if you need to drag DIV elements across both tables, but dragging rows should stay within a table, then this can be done by using event handlers. If myhandler_row_dropped_before event handler returns false then row dropping will be cancelled. So, you can detect source TD, and target TD, try to find parent TABLE element and if is not the same for source and target TD element then return false.

  2. Many thanks Darko, not just for the reply but this awesome awesome app! FWI: just donated via Paypal. Keep up the good work.

    Alex

  3. Hi everyone,

    Is there a way in the example 3 to extend an “event” into many cells.
    for example I have “Maths” from 8am to 9am, I would like to extend the event from 8am to 10am.

    Thanks in advance for your help

  4. @Alex – I’m glad that the trick with class name has solved the problem. Your donation is very appreciated and it will help me to continue developing/supporting REDIPS.drag library.

    Thank you very much!

    @Eric – Example03 School timetable currently doesn’t have an option to merge table cells. I can only suggest you to place several DIV elements in a column to mark “Maths” from 8am to 10am. However, please take a look to the REDIPS.table lib. It’s a new small utility with merge/split options. Please try to click on table cells and then merge them vertically or horizontally. REDIPS.drag and REDIPS.table can work together. First one gives ability to drag DIV elements while second adds dynamic table modification.

  5. Darko,

    This app is AWESOME! I’ve messed around with other drag-and-drop apps but yours is, by far, the best I’ve come across. Excellent work!

    A quick question… I’m working with example21 and I wanted to add automatic saving once a cell is moved, but have been unsuccessful so far. I was able to add the save functionality from example03, where after a cell is moved and the ‘Save’ button is clicked, the window pops up with the new table order. I was wondering if you could point me in the right direction on how to save automatically? So, for example, in example21, if I moved cell ‘O’ from 3-0 to 2-2 I’d want the save function to pop up the order window without having to click a button. Any direction or assistance you can provide is greatly appreciated.

    Thanks, in advance, for your help and thanks, again, for such a great app.

  6. @Brian – I’m glad you like REDIPS.drag library. It’s very flexible and I hope it will fit for some cases :)

    I think you can see the add-on inside example03/ajax directory where I prepared AJAX save on every DIV element drop. Here is text from example03/ajax/readme.txt file:

    ... AJAX variant of demo. To enable AJAX method, open index.php
    in parent directory and replace the following line:
    
    <script type="text/javascript" src="script.js"></script>
    
    with:
    
    <script type="text/javascript" src="ajax/script.js"></script>
    
    Printing subjects or spreading school objects across week are
    not supported in AJAX demo.
    

    With activation of ajax/script.js every move will be saved to the database. Hope this will give you an idea how to solve the problem. If you will have further questions, I will gladly try to help. Cheers!

  7. Hi,
    It is possible to get the value of the input(Text box) after pressing the save button?

  8. @Jacky – Built-in save_content() public method will search only for DIV elements, their id and position in table. Found data will be prepared as a query string or JSON format. As you can see in source code starting at line 2912 (redips-drag.js file), save_content is pretty simple method/function. With some basic JavaScript skills it can be easily customized to search any form element within DIV and to append value to the output.

    So generally speaking, yes it’s possible to get the value of the input box. If you will get stuck in solving problem please send me your example and I will try to help you.

  9. @dbunic
    I got it already, thanks for the hard work, it make my work a lot easy :D

  10. Hi,

    I want to move 2 columns together. Any help will be appreciated.

    Thanks in Advance!
    Hrishikesh

  11. @Jacky – I’m glad you found a solution and thanks for using REDIPS.drag library.

    @Hrishikesh – Unfortunately, REDIPS.drag hasn’t ability to move table columns. It’s posible only to drag/move DIV elements across tables and table rows (one by one).

  12. Hi dbunic,
    you have a done a great work with this drag&drop application. I am relatively new to coding, so I guess, there are no stupid questions. :-)

    I’d like to change to the disable the message function of the cell. How can I do this? If I disable the cell with the id=Message or id=msg, the d&d won’t work. Any ideas? Thank you in advance.

  13. @Mario – msg is the reference to the table cell with id=”message”. It’s used to show message from event handlers in a drag and drop process. If drag and drop stopped to work after you made change then is possible that you have an error in the code. You can open Web inspector and search for the JavaScript error in console. Google Chrome will open Web inspector with Ctrl+Shit+i keys …

    Google Chrome Developer Tools: 12 Tricks to Develop Quicker
    http://www.youtube.com/watch?v=nOEw9iiopwI

    My guess is that error in event handler stops REDIPS.drag library to work but you can get more info in Web inspector console.

  14. Hi dbunic,
    found a solution. disable rd.myhandler! :-)

    But I’ve another question. I added an image zoom to the cell content. when I clone this content with mouseover the mouseover state will be the cloned. For e.g. img with mouseover is w=200 and h=200, but the original cell image is only about 50x50px. the bigger ones get cloned.

    How can I only clone the original size?

  15. Thank you for your fast response. Well, pls excuse my last comment. I am new to coding. :-)
    I changed my css with:

    #img:hover{width:130;...}
    

    … and it works like a charm. Could I add a personal value to each cell and generate an output of the selected ones? Let’s say 5 cells have a different content and i can select through drag and drop a mixture. e.g. cell 1=123, cell 2 = 234, and so on. And i choose a new row let’s say cell 1, cell 1, cell 2, cell 2, cell 2. Am I able to generate an output? Thanks in advance. And I am going definitively to support your awesome work.

  16. @Mario – I’m glad you solved the problem, using REDIPS.drag lib should be easy. ;)

    Anyway, REDIPS.drag has built-in save_content() method to scan table for DIV elements and return result as query string or JSON. Location of every DIV element is defined by row/column index because table cells are used as dropping layout. So, prepared output (in both cases) will contain DIV id and location of DIV element (row and column index). Selecting DIVs can be done in a way to have a separated table where DIV elements will be dropped. Then is only needed to call save_content() method with index of that table and the output will be automatically prepared (ready to send to the server). Other approach is to call AJAX save on every DIV drop to the defined area (special cell or table). You can find both cases (save complete table content and using AJAX on every DIV drop) in example03 – School timetable. Examples are prepared for PHP and MySQL on the server side but it can be easily modified for ASPX, JSP or other script.

  17. Hi,

    Read a post here about append the value (ex. textbox) of a tablecell in save_content to the json return
    I can’t get it to work, could anyone please help?

    JSONobj.push([cn.id, r, c, cn.nodeValue]); // ????
    
  18. Hi,

    In the save_content function, how could I retrieve the content of a input text box that is placed in a cell?

  19. It’s always a joy to find gems like this. This one is definitely being added to the treasure chest… :-)

Leave a Comment