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. For some reason, .. I can’t seem to replicate the “Scrolling Div Containers” example (as shown here):

    http://67.199.17.112/redips/example5/index.html

    Can anyone here help me determine why my version of this isn’t working correctly?

    http://67.199.17.112/progressionplans.php.htm

    I realize only one of my DIVs is in a scrolling window, .. but even when I put the other one in a scrolling DIV, I still can’t get the drag and drop to work.

    Why am I not able to drag and drop courses from the scrolling list on the left into the student progression plan on the right?

    Thanks,
    – Yvan

  2. @Rat – Have you managed to move created input box? As I can see, element with input box is movable so I assume that you solved the problem … Nice work!

    @Alfredo – Maybe the drag area isn’t big enough? Please try to make it visible:

    #drag{
        border: 2px solid red;
    }

    … my first thought about causing the problem. As you can see on this demo, dragging input field should work without any restrictions.

    @Yvan – please try to add the following rule to the kaplan.css:

    /* drag container */
    #drag{
        height: 700px;
        width: 1000px;
        border: 1px solid lime;
    }

    This should enable dragging …

  3. Hi everybody, is there any oportunity, to use this script with Javascript Framework mootools, iam planing to use it, with a ajax request and to genarate the Left Table of the 3th example with ajax, and then to drag and drop the subjects into the right table. So i want to make it possible to upgrade the left table, with other subjects. But the problem in this case is, that i dont know how to make it possible, because your scripts needs to have fix html tables in the php file, and my ajax request is just showing me the html content i requested, so the drag and drop doesn’t work because he is missing the table structure in the file. Have you any idea how i can manage that ?? Please iam not a pro in javascript like you guys.

    Sorry for my english iam from Germany and your script is great, could you please help me to solve my Problem

  4. Hi everybody, i don’t know if my last posted had been posted, but i have a problem with some stuff with the example 3. I want to include your great script example three on my page to do some student subject stuff. Iam working with mootools ajax request. My question is i want to update the left Table of example 3 with other subjects and then i want to drag and drop them to the right subject table. The problem is, the php page i request that responses me the generated sql data with the correct table syntax of your script. After the ajax request was successful iam replacing the left table content with the html request. After this is done iam trying to drag and drop the subjects to the right table but it doesnt work. When iam looking on the side code on firefox he isn’t showing me the content on the page because ajax is just not including the code in to the php file it just shows the contnent, iam not professional in javascript, can you help to fix this problems to make your script working with this particular problem, if iam using fix code like … <div<.. etc it works but if iam working with ajax request an replacing the code the script doesnt see the dragable divs. Please could you help me with this problem please to solve it thank you very very mutch, – Harris

  5. I’m becoming very frustrated with myself for not being able to figure this out. I’m certain there is a simple answer, but I can’t seem to find one that I can comprehend from the previous comments. So I’ve finally broken down and am asking for your help. :)

    Please keep in mind that I am only generally familiar with Javascript and this is my first time working with PHP.

    Here’s what I’m trying to understand…

    In Example 1, there are 3 input fields. One is a text box marked “content”. The others are the sets of radio buttons and checkboxes. My understanding is that I can fill in the text box (or click a checkbox or radio button) and move it to a cell within Table 1. Then I would assume that upon clicking “Save”, the new “Available Parameters” windows should display the values of my text box and buttons somewhere on the new page. However, it only displays the ID, row and column numbers.

    What am I missing here? I’ve tried making various alterations to the code in the index.html, drag.js, and multiple_parameters.php files, but nothing I’ve attempted thus far has resulted in the content/values being posted.

    When responding, please presume that I know nothing about JS and be detailed in any explanation you give me.

    Thank you very much in advance for your help! You’ve developed what appears to be a fantastic script and I’m looking forward to using it.

  6. @HG – I’m glad you solved the problem. I would be even happier if you would comment the solution. Thank you!

    @DMO – “Save” button in Example1 collects table content – DIV objects. Some DIV objects can contain form elements. If you want to post form content, then you have to put table1 in <FORM> and define ACTION attribute. Next, you only need submit button to enable form submitting. This should be enough for form submitting.
    ;)

  7. Darko, thank you very much for your prompt reply. Unfortunately, I’m still confused. Perhaps I should be more specific as to what I’m attempting to do.

    Let’s say I would like to have the word “hello” appear in the new Acceptable Parameters window. So using the text box in Column 0 Row 4 of Table 2 that currently says “content”, I’d like to delete the word “content”, insert the word “hello”, then drag the entire text box up to Column 1 Row 1 of Table 1. Upon doing so, clicking “Save” will presently result in the following:

    Id=d1 Column=0 Row=1
    Id=d13 Column=1 Row=1
    Id=d2 Column=2 Row=1
    Id=d3 Column=3 Row=1
    Id=d4 Column=0 Row=2
    Id=d5 Column=4 Row=2…

    Now, what I want to see happen is for the word “hello” to appear somewhere in the second row, along with “Id=d13 Column 1 Row 1”. In other words, I’d like the VALUE of the text box (“hello”) to be displayed in the new window corresponding to the cell where I moved it on the main (index.html) page.

    Id=d1 Column=0 Row=1
    hello Id=d13 Column=1 Row=1
    Id=d2 Column=2 Row=1
    Id=d3 Column=3 Row=1…

    or possibly something like…

    Id=d1 Column=0 Row=1
    Id=d13 Column=1 Row=1 Name(Value)=hello
    Id=d2 Column=2 Row=1
    Id=d3 Column=3 Row=1…

    Can this be accomplished using the form-submitting method you suggested? Will using the form action result in the value “hello” beomh placed in the correct location in the new window? And if so, what form action should I use, post? Also, what needs to be changed in the multiple_parameters.php file to accommodate the text box value?

    As you can see, I’m still quite lost. Any additional help you can provide would be greatly appreciated. :)

  8. Hi,
    I’m currently using this and its’ drag-n-drop functionality is working great so far. I’m encountering problems when I try to integrate this together with a freeze header / 1st column table. There are quite a number of such jquery api’s out there, but so far, I can’t seem to get both the frozen header & the drag functionalities to work together.
    Can you recommend any freeze header /1st col jquery api that works with this? Or, is there anything particular i need to configure/ensure at either end?

    FYI, I’m using drag.js version 2.2.1

  9. Hello All,

    This is great! Exactly what I need.

    I have got few problems though, please help me.

    I’ll populate a table with single cell (1 row, 1 column) with all the content in this cell. The content will be coming from database (Its a jsp). Now I ll drag the contents and I want rows and columns to be added or removed according to the drag.i.e if I drag a content horizontally at the end of the table…new column gets added. Similarly new row should get added when I drag the content vertically.
    Is it possible to add it in same js above?

    Also I am unable to get the save button function correctly.

    I download and save the js, html and php file properly. Still on click of save I am getting a popup giving me the code of php or parapmeters but not the values as it show here.

    Please suggest.

    Note: I know very little of js if compared to this stuff, so kindly give a coded solution or functions I need to add in this and make it work :)
    Thank You
    SP

  10. I don’t know if my last query got posted or not.

    Here it is once again.

    I have imported this in my application and it is working great for me. Thank you so much.

    I need new help though. I am calling all the elements that need to be arranged in a table with single cell(1 row, 1 col)
    from database.(its a jsp). Now, When I drag elements horizontally new column should get added and if vertically new row should get added.

    Also my save button is not functioning properly despite my php file is in proper location. I want the total no. of columns and rows of this new table created.

    Note: Compared to this stuff you have made…I know nothing of javascript. Please help me by providing code snippet.

    Thank You
    Sandy

  11. Hi Darko, thankyou for releasing this code. ive been playing with it all day, and i’m loving it, really great job mate. :) I have a question though, i hope is easy to awnser!

    Currently screwing around with example3, changed the dragable text in the left menu into images(50×50).I can disable REDIPS.drag.drop_option to allow multiple drops in the cells on the right, but what i really want to do, is to be able to drop each dragable image only once in each cell. and in a line, instead of ontop of each other as now.

    is there an easy way to do this do you think? your time will be appreciated.
    regards, Pete

  12. Hello All,

    The Tables are shown one over other. If I put them next to each other horizontally what will be the div positions?
    I put both tables in a table_main columns but the tables itself become dragables. I want to move the content of the tables shown here horizontally.

    Please help

    Sandy

  13. Sorry, that i haven’t posted the solution, but i just forgot to call the Init Function, after i made some Changes in the Left Table with javascript (Changing Content).

    best regards, HG

  14. Hye,

    Firstly – this is such a good library, thanks! Is it possible to make objects infinitely clone-able (ie. drag cell to another cell to clone, then be able to clone continusouly? Also, I may be being stupid, but how could I make it so that if I drag a box into a cell, it overwrites the old contents? (for example having a table full of “yes” boxes, and rather than drag the yes box to the trash to replace it with a no; i just drag the no box over yes and it replaces it)

    Cheers
    Bill

  15. Hello DBunic,

    Is it possible that I drop that element such that it can span for more than one cells.
    i.e. is the spanning of the draggable elements possible?

    The solution which I have thought of is to call a popup box where user can input the colspan and rowspan and the element is arranged accordingly

    need some support to make it successful.
    Thank you
    Sandy

  16. I’m sorry, but does anyone know if Darko is still providing support for this script? I’ve searched the comments going back to over a year ago and this is the longest he’s gone without posting, his last post being the 1st of July. I was just wondering because I’m still lost as to how to accomplish my desired result with this script and I’m desparate for help, so I’m checking in most every day. If anyone knows if/when he might return or can themselves provide some help, it would be greatly appreciated. Thank you.

  17. Sorry guys, because of few deadlines in August I wasn’t able to post comments. Hope in the coming period I will have more time.

    @DMO – save_content() function scan tables and search only for DIV elements. Table cell can have more than one DIV element. It’s possible to add the name/value of the form element but DIV element can contain many form elements. So, solving this issue generally would not be simple and this would complicate the script. But, if your case is one form element (text box) per DIV, that shouldn’t be difficult to implement.

    Find the line 1330 in drag.js and instead of:
    if (tbl_cell.childNodes[d].tagName === ‘DIV’) { // and yes, it should be uppercase
      query += ‘p[]=’ + tbl_cell.childNodes[d].id + ‘_’ + r + ‘_’ + c + ‘&’;
    }

    Place the following code:
    if (tbl_cell.childNodes[d].tagName === ‘DIV’) { // and yes, it should be uppercase
      frm = tbl_cell.childNodes[d].getElementsByTagName(‘INPUT’);
      if (frm.length != 0) {
        frm_name = frm[0].name;
        frm_value = frm[0].value;
        query += ‘p[]=’ + tbl_cell.childNodes[d].id + ‘_’ + r + ‘_’ + c + ‘_’ + frm_name + ‘:’ + frm_value + ‘&’;
      }
      else {
        query += ‘p[]=’ + tbl_cell.childNodes[d].id + ‘_’ + r + ‘_’ + c + ‘_&’;
      }
    }

    You should also define variables in function head:
    var frm, frm_name, frm_value;

    This will add the fourth parameter with input text name and value.

    And finally, modification in multiple-parameters.php

    foreach ($arr as $p){
      // detach values from each parameter
      list($id, $row, $column, $frm) = explode(‘_’, $p);
      if ($frm) {
        list ($frm_name, $frm_value) = explode (‘:’, $frm);
        print “Id=$id Column=$column Row=$row $frm_name=$frm_value<br>”;
      }
      print “Id=$id Column=$column Row=$row<br>”;
    }

    Hope this will help …
    PS don’t forget to define “name” attribute for text input element.

Leave a Comment