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. @Vlad – Well, my guess is that it can be done using some styles to the TD cell. Please see example13 where circle and rectangle DIV elements are dropped in the same cell.

    @mie – Hi, to save DIV elements you’ll have to create service (using servlet, PHP …) that can read JSON data (preferred). REDIPS.drag library already contains method for scanning table and preparing data in JSON format. Just click on the “Save2” button on example1 to see the output from REDIPS.drag.saveContent()

  2. Hello:

    Great product, but I’m having a little problem. I have six tables sitting next to each other. Two of them are off screen, so when I scroll to bring the tables into view, I guess it wants to keep its original position, not counting for the offset. Is there any way to fix this?

    For example, you can see it happening in your Example 06. Move the scroll bar to the right and try dragging and dropping. It fails.

    Thank you so much in advance.

    Frank

  3. Hello everyone.

    I’m trying to use Example 01, although i can’t get cell to drag.

    I’m trying to adapt this example to my code, so I put some of “index.html” code into my .html, I’ve put all the scripts and copied the .css and .js . Tha tables appear, everything is nice and well formated, the real only problema I’ve got is that I’m not able to drag.

    Any tips or help?

  4. Hello, first of all thanks for Redips, it is a really fantastic library!
    I’m trying to insert (or delete) an item in the table by clicking a specific button (bypassing the drag and drop system).
    Using as a basis the example 24 (table editor) i’m not able to get anything.
    Is it possible to obtain this? Should I use cloneObject method?

    Thanks so much
    Maurizio

  5. @Maurizio – To delete DIV element you can use deleteObject(el) metod. Here is example from documentation:

    // delete DIV element in event.dropped() event handler
    rd.event.dropped = function () {
        rd.deleteObject(rd.obj);
    }
      
    // delete DIV element with id="d1"
    rd.deleteObject('d1');
    

    On the other hand, if you want to dynamically add new DIV elements to the table, it’s needed to run enableDrag() method. Here is example how to reinitialize all DIV elements on the HTML table:

    // init DIV elements in dragging area (including newly added DIV element)
    // DIV initialization will work if table node stays intact (table is not generated dynamically) 
    REDIPS.drag.enableDrag('init');
    

    It’s also possible to init only new added element (please see docs for enableDrag())

  6. Hi Dear

    I have some problem with Drag & Drop these script. When i Return Data from ajax and php with whole html table design, then it is now working drag script. So please can you help me. How can do solve it for these problem?

  7. Hi.

    In example 23 is is possible to pre populate the ‘drop_list’, and still have the ability to add and remove new and existing entries ?

    I’ve tried using JS to append a new to the drop_list and this works, but I then don’t have the ability to remove the entry.. if needed.

    Any idea how I can do that ?
    Thanks

  8. Hot to retrieve data and fill table

    Based in example #3, i store data into 2 columns, Grupocodigo (the object code) and Position.
    i create this function, and call it from redips.init part:

    function cargagrupos(rd) {
        var xhttp=new XMLHttpRequest();
        var url = 'llamadasajax/leerhorario'; //---> use your appropriate ajax call to retrieve data!!
        xhttp.onreadystatechange = function() {
        if (xhttp.readyState == 4 && xhttp.status == 200) {
          //document.getElementById("demo").innerHTML = xhttp.getResponseHeader('Last-Modified');
          var datos = JSON.parse(xhttp.responseText);
          //loop to read data and move each item to cell
          datos.forEach(function(valor) {
                var grupocodigo = valor['Grupocodigo']; //lectura desde b.d.
                var objeto = grupocodigo.substring(0,3); //el objeto fuente
                var objetodom = document.getElementById(objeto);
                //leemos y procesamos la posicion
                var posicion1 = valor['Posicion'];        
                var posicion = posicion1.split(',').map(function(item) {
                    return parseInt(item, 10);
                    });
               
                //insertamos en posición  
                var objNew = rd.cloneObject(objetodom);        
                rd.moveObject({
                obj: objNew,
                target: [posicion[0],posicion[1],posicion[2]]  //table,row,cell
                });
                
            });
          
        }
      };
      xhttp.open("GET", url, true);
      xhttp.send();    
    }
    
  9. very nice product but only one simple problem I am facing is how to find the column and row number of a cell during dropping something into it. I tried my best but didn’t find a suitable solution.

  10. @Murad Khan – You can use rd.td.target property to access target TD element. From this reference is possible to read cellIndex property and go to parent element TR for rowIndex.

    Please see docs for “td” property in Field Summary section.

  11. I am working on timetable module. Dragging subjects to the table works fine on my localhost but does not work on live server. I do not get even a JavaScript error but still it is not working.
    Please help me in this regard.

  12. Hi Mareena,
    if you can provide URL for your public site, I’ll try to see where is the problem.

  13. How can i get the ID of a target DIV?
    I can get the ID div of my draggable DIV but not my droppable target?
    Its is possible?

  14. Can you please give me your contact? I have a lot of questions to do. Thank you :)

  15. it works great on plain html.
    is it posible that your scripts also will work on asp.net with Master page with twitter Boostrap?
    (Example 9: Single and shift mode)

  16. I’m trying to create a large drag and drop table (27 columns x 15 rows) so that I can plan lorry delivery schedules.
    I’ve hard-coded the table into the screen and then using json/dexieJS populated the large tables with div’s that represent towns. At the end of the populating from the JSON array, I then call REDIPS.drag.initTables(); to force the table I’ve just amended to be initialised again.

    The table works fine for the first 17 columns (routes) and I can drag and drop any of the towns (91 of them so far) into any of those 17 columns, from then on, the remaining columns (18-27) will not drag and drop the divs into empty cells.
    There is no difference with any cell I generate, (common code) it’s just that columns 18 onwards don’t work.
    columns 1-17 clearly show the startDrag, shading of the TD as it’s moved over other cells and then it’s all cleaned up onDragEnd.
    columns 18-27 on the other hand, shows the startDrag, shading of the TD and then nothing from then on. (I would expect the TD shading to transfer to other cells as I drag over them.)

    its as though the REDIPS has “run out of memory” and can’t handle the drag/drop any more.

    Is there anything special that needs to be done when hadling large tables?
    kevin

  17. @Kevin – The problem might be related to size of drag container. Please try to add the following lines to your style.css file:

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

    After page refresh, drag container will be visible. My guess is that right columns exceeds out of drag container and that’s the reason of problem.

  18. Hi, am using your app for 4 years. I optimised it for our enviroment and extended about many functionalities. It is EXCELLENT application. Nowadays we want use app on tablet (10 inch). I am working in company. There is many rooms ( 17 columns) with many people (about cca 6 row)… daily approximately about 60 cells for use. This is a big problem when user wants to move cell on tablet. When user moves one cell between other cells this one doesnt move to other position like he wants. What solution do you suggest to me for suitable usage. Is there any solution for mobile devices? Thank you.

  19. This is a great post, I am working on a project where 9 lorries do concrete deliveries in 5 slots during the day.

    I need to design a 2 way table with drag drop facility. I have followed example 00 where we can simply drag and drop. My Question:
    1. How can I get the value along with content_id?

    Example:
    Let’s i have job id=2 in column 2 row 3, but then I need to change the lorry and timing so I drag to it column 3 row 4 now i need to save these details for same job id.

    So, on drop i need to save this data.

    how can i achieve this ?

Leave a Comment