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)
- for unlimited cloning add “redips-clone” class name to the DIV object
- 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!
@Mark – Please download latest REDIPS.drag (version 4.7.3) and try the following code. This will append innerText from the bottom DIV element to the dropped DIV element:
@dbunic
Wow buddy. This works great :) I can’t describe in words that how much helpful you are. It feels great to meet people like you.
Well, there are more questions which I may be asking in future if I may not be able achieve some other goals.
Thanks once again.
Well, I think I should ask those questions right away :D
1) Is it possible to apply different drag options on different tables. Like in one, switching is enabled and other one has the overwrite feature?
2) Say, “table 1” has different data cells consist of three different types (a, b and c) only that DIV can be moved to “table 2” which is the “resultant” after merging exactly three DIVs of exactly three types (a, b and c). How it can be achieved? There should be other restrictions like one DIV may contain exactly one type at a time. For e.g. “resultant” may consist of type {a, b and c} only. No { a, a b } no { a b b} etc…
@dbunic,
Great thing you are doing here. one thing though: After dropping the cell, when saving, how can I get a specific ID for the row instead of the table index? I have a key column, which is not ordered, and I need to know where was my cell dropped so I can update my records with it. Am I missing something?
Thanks and best regards,
Amit, Israel
@Mark
1) Yes it’s possible to change “drop option” based on bottom table. Please see example09 where drop option is changed in myhandler_moved() event handler. Here is code snippet:
2) If you want to allow dropping only DIV elements with content “ABC” to the second table here is simple JS code in myhandler_dropped_before() event handler:
The same can be done with content merging. It’s only needed to compare strings of bottom DIV element with text in dropped DIV element. The posted solution is not a perfect because DIV content should be split before comparison but I hope it will give you a right direction how to solve the problem.
@Amit Nevo – Here is how to obtain TR id of dropped DIV element:
@dbunic
Thanks for the rapid reply, but please allow me to pinpoint the question? can I get this in the save function? I need my server to get the id when pressing the save button, after all changes have taken place. what function do I need to incorporate this?
Many thanks and sorry about the bother,
Amit
@Amit – Well, REDIPS.drag doesn’t have built-in option to send row ID but here is how to get such functionality. From the redips-drag.js file copy save_content() method to your script.js file. Rename save_content to mysave_content. You will need to declare mysave_content below redips_init like:
Now you can customize mysave_content to send row ID. Declare “row_id” variable and replace:
with:
This modification will send row ID instead of row index to the server side.
I am creating dynamic with JavaScript and would like one TD element to be able to be dragged to another dynamic table.
To create I do the following:
It shows as clickable but the event never reaches your handler.
If I have a static row I can Items from there and place them in the dynamic table.
Is there anything I can try?
BTW it is a very nice library and is easy to implement.
Ben
@Ben Levy – First try to make drag container visible. If newly created TD exceeds drag container then it will not be accessible for dragged DIV elements:
Next, dynamically created DIV element (and added to the table) should be initialized. Re-initialization can be done with calling REDIPS.init() method, but the better approach is to call enable_drag() to avoid overhead. Here is a code snippet from documentation of how to call REDIPS.drag.enable_drag():
Hope this tips will help.
Hello,
first I would like to say a big thank you for your wonderfull work. You are very gifted. And my question is : is it possible to draw a div of not only one cell but 2 or more cells.
Thank you very much.
Hi,
thanks for the great script, just one question, how can i add more element on example 22, where i can drag the element from left column to the right column, and after dragging the option page will open.
Is it possible for me to drag more than one item to the right column?
@farinis – One DIV element can be dropped to only one table cell. So direct answer to your question is “no, it’s not possible”. But if you take a look to the example 24 Table editor, you will see that bottom table can be dynamically modified. Rows can be added / deleted and table cells can be merged and split. Table functionality is achieved with REDIPS.table library. So, cells can be first merged and then dropped DIV element will strech to fill merged cells. DIV width is set in myhandler_dropped_before() event handler.
@Eizil – Your question is similar to the farinis’s question, so the answer will be also similar ;) It is possible to drag only one DIV element at a time. But you can use a trick and mark other DIV elements that should be moved as well. Please see example 12 Select and move more elements. Try to mark few DIV elements and make a move. You will see how marked DIV element will be moved to the destination cell. Animation is optional and moving marked DIV element can be instantly.
@dbunic
Thanks for your suggestions. My website is getting interesting day by day after implementing your suggestions. As usual I have some queries. When I’m using the event, myhandler_moved(), this line is not able to search the parent table id and returning null, when the moving div option is set to ‘clone’:
Except for clone, it is working fine. Also, tell me that I want to catch the id of deleted element after user presses OK on the confirm dialog result. And pass that id to my own function. Kindly point me to the right direct (as you always do :D)
Thanks in advance.
@Mark – For the first question please download new redips2.tar.gz package – version 4.7.5. In latest version, myhandler_moved has optional input parameter “cloned”. This is needed to know whether current DIV element is cloned or not. In case when DIV is cloned then origin for table search is rd.obj_old. Here is complete code:
rd.ob_old is also needed to catch the id of deleted element:
Hope this will help …
that’s perfect :)
many many thanks…
@dbunic
Hi,
Great Code,
I have a question. I am working with example 24, but when I drag a block to the right cell, I need to create a new cell, so I just need 1 row with N cells. Is there a function to do it?
Regards
Orlando Ibarra
Thanks for everything
Thank you for great code!
I have trouble executing the JavaScript code using AJAX call. Is there a way around this?
@dbunic – Firstly I want to thank you for a great library, I just wanted to ask your advice if I may? I am using example 3 but want to use an extra table called ‘room’. I have successfully got 2 cells for each time slot, one for room and one for subject, and I have been able to add an extra table with room numbers to drag to the timetable. When I save it the room is successfully saved to the database but is doesn’t display in the table. I would really appreciate any help here, Thanks
@Orlando Ibarra – Yes, new row can be created with REDIPS.table.row(table, mode, index) method. Please download redips12.tar.gz from Merge and split table cells with JavaScript page where you will see several examples. REDIPS.table also has a documentation page.
@Jim – You can find several examples using REDIPS.drag and AJAX:
I also wrote a post about AJAX progress bar with a live demo so you can see all needed details and how to make it in a cross-browser manner.
@Tatty27 – Please take a look to the timetable($hour, $row) PHP function in config.php file. After timetable (with room numbers) is saved to the database, try to execute select query located in “timetable” function with MySQL Browser, MySQL Workbench or phpMyAdmin. Rows with room number should be fetched also. If they exist in record set, then try to print out $elements array with the following line:
And the last step is to place print $elements[$i] inside for loop:
Your problem is on the server side, so you only need to tune PHP variables. Hope this simple “print” technique will help you in debugging PHP code.