Drag and Drop table content with JavaScript
Content of HTML table cells can be dragged to another table 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 destination table cell. Attaching onMouseOver handler on table cells will not work, because browser doesn't fire events to the elements beneath the dragged object.
Anyway, after taking care of the current scroll position and calculating table cells positions, here is example that should work in FireFox 3, Internet Explorer 6 / 7 / 8 and Google Chrome. Please try to drag green, blue or orange bordered objects, change properties (radio button and check-boxes) and click on "Save" button. Funny, isn't it?
| You | can | not | drop | here |
|
Drag
|
and
|
drop
|
||
|
content
|
|
|||
|
with
|
||||
|
JavaScript
|
||||
|
|
| Table2 |
and
|
|||
|
Drag
|
drop
|
table
|
||
|
|
||||
|
with
|
JavaScript
|
|||
| Table3 |
|
|||
|
Clone
|
||||
|
(1) Clone
|
(2) Clone
|
|||
|
|
Trash |
You can try another example built on this Drag and Drop library.
"Save" button will scan tables, create query string and send to the PHP page. Demo shows how to collect table content and accept parameters on the server side. More about accepting parameters you can read in my post Reading multiple parameters in PHP. Orange object "Clone" will be duplicated first because of "clone" keyword in his class name. If you drop object on cell named "Trash", object will be deleted from the table (with or without confirmation). Script has built in autoscroll and option to forbid landing to non empty cells or cells named with class "forbid". Table can contain rowspan / colspan cells and different background color for every cell.
Here are minimal steps to enable content dragging in table:
- put <script type="text/javascript" src="drag.js"></script> to the head section
- place table(s) inside <div id="drag"> to enable content dragging
- add .drag{position: relative;} class to CSS file
- place <div class="drag">Hello World</div> to the table cell
Other features of drag.js:
- functions and data structure are defined in namespace (easier integration with other JS frameworks)
- JSLint: No problems found in drag.js (tough one, huh)
- movable div element can contain form elements and links
- forbidding or allowing table cells marked with class name "mark" (depends on "marked_cell" parameter)
- option to define exceptions and allow certain DIV elements to the marked table cell
- option to define single content cell on the table declared with "multiple" drop option
- cloning
- for unlimited cloning add "clone" class name to the div object
<div class="drag clone">Hello World</div> - to limit cloning and transform last object to the ordinary movable object add 'climit1_X' class name
<div class="drag clone climit1_4">Hello World</div> - to limit cloning and transform last object to immovable object add 'climit2_X' class name
<div class="drag 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 "clone" class name to the div object
- allowed nested tables
- dropping objects only to empty cells
- switching content of table cells
- table cell with "trash" class name becomes trashcan
- enabled handlers to place custom code on events: clicked, moved, not moved, dropped, switched, cloned, cloned end1, cloned end2, deleted and undeleted
- deleting cloned div if the cloned div is dragged outside of any table
- enabling / disabling dragging
How drag.js works?
Script will search for div elements (with class name "drag") inside tables closed in <div id="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 "left" and "top" styles of the object. 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 mouse move events only when user holds left mouse button on div element.
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 table cell coordinates (with scroll page offset) and store them to arrays. Arrays are searched inside onMouseMove handler and after left mouse button is released, object will drop to the current (highlighted) table cell.
In redips2.tar.gz (17KB) package you will find demo (more examples) and well commented source code. Instead of including original JS file, I will suggest to compress it first and it should look like drag.js file included in this post.
Happy dragging and dropping!
@dbunic :
Sorry, my bad.
Now those has been deleted. But the main problem still remains. If I make a rowspan=4, the whole td wont move - just the div inside. I assume that this script has been designed this way but is there any change to move the td instead the div inside?
My purpose is to make similar content moving system than this: http://arshaw.com/fullcalendar/ (click on the "week" -view.)
Thank you so much dbunic, the single cell class works perfect. AWESOME
@joekki - Unfortunately drag.js library is designed to move table content only. Moving TD means to modify HTML table and such functionality isn't supported yet.
@CaptainPlum - I'm glad it works ... Cheers!
Thank you dbunic. I tried your suggestion (commenting the 2 lines to also use nested tables). So now I have this kind of structure: Parent Table has 2 columns - Column 1 contains my source table and column 2 contains my target table. When I am moving the cell from source table, it is not identifying any cell in target table, where I can move. In the case, where I do not have the parent table (no nested structure), everything works fine. Any idea why this may be so?
@Rajesh - Script scans table rows of all tables inside <div id="drag">. In your case table row of nested table is overlapping with parent table and that might be confusing. Because of that reason, tables in deeper hierarchy are ignored (two commented lines). If you need parent table only to establish page layout, you can use DIVs to place tables (source and target) side by side. Placing tables with DIVs instead of parent table should work without problems.