Table Drag and Drop JQuery plugin
I’ve been using JQuery for a while now and really agree with its tag line that it’s the “The Write Less, Do More, JavaScript Library”. We’ve also got this code for dragging and dropping table rows that has proved very popular, so it seemed natural to combine the two and wrap up the table drag and drop as a JQuery plugin.
Why have another plugin?
Dragging and dropping rows within a table can’t be handled by general purpose drag and drop utilities for a number of reasons, not least because you need to move the whole row, not just the cell that receives the mouse events. Re-parenting the row also requires specific code. Sadly also, effects like fadeIn and fadeOut don’t work well with table rows on all browsers, so we have to go for simpler effects.
What does it do?
This TableDnD plugin allows the user to reorder rows within a table, for example if they represent an ordered list (tasks by priority for example). Individual rows can be marked as non-draggable and/or non-droppable (so other rows can’t be dropped onto them). Rows can have as many cells as necessary and the cells can contain form elements.
How do I use it?
- Download Download jQuery (version 1.2 or above), then the TableDnD plugin (current version 0.5).
- Reference both scripts in your HTML page in the normal way.
- In true jQuery style, the typical way to initialise the tabes is in the
$(document).readyfunction. Use a selector to select your table and then calltableDnD(). You can optionally specify a set of properties (described below).
| 1 | One | some text |
| 2 | Two | some text |
| 3 | Three | some text |
| 4 | Four | some text |
| 5 | Five | some text |
| 6 | Six | some text |
The HTML for the table is very straight forward (no Javascript, pure HTML):
<table id="table-1" cellspacing="0" cellpadding="2">
<tr id="1"><td>1</td><td>One</td><td>some text</td></tr>
<tr id="2"><td>2</td><td>Two</td><td>some text</td></tr>
<tr id="3"><td>3</td><td>Three</td><td>some text</td></tr>
<tr id="4"><td>4</td><td>Four</td><td>some text</td></tr>
<tr id="5"><td>5</td><td>Five</td><td>some text</td></tr>
<tr id="6"><td>6</td><td>Six</td><td>some text</td></tr>
</table>
To add in the “draggability” all we need to do is add a line to the $(document).ready(...) function
as follows:
<script type="text/javascript"> $(document).ready(function() { // Initialise the table $("#table-1").tableDnD(); }); </script>
In the example above we’re not setting any parameters at all so we get the default settings. There are a number
of parameters you can set in order to control the look and feel of the table and also to add custom behaviour
on drag or on drop. The parameters are specified as a map in the usual way and are described below:
- onDragStyle
- This is the style that is assigned to the row during drag. There are limitations to the styles that can be
associated with a row (such as you can’t assign a border—well you can, but it won’t be
displayed). (So instead consider usingonDragClass.) The CSS style to apply is specified as
a map (as used in the jQuerycss(...)function). - onDropStyle
- This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations
to what you can do. Also this replaces the original style, so again consider using onDragClass which
is simply added and then removed on drop. - onDragClass
- This class is added for the duration of the drag and then removed when the row is dropped. It is more
flexible than using onDragStyle since it can be inherited by the row cells and other content. The default
is class istDnD_whileDrag. So to use the default, simply customise this CSS class in your
stylesheet. - onDrop
- Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table
and the row that was dropped. You can work out the new order of the rows by using
table.tBodies[0].rows. - onDragStart
- Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the
table and the row which the user has started to drag. - scrollAmount
- This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the
window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2,
FF3 beta)
This second table has has an onDrop function applied as well as an onDragClass. The javascript to set this up is
as follows:
$(document).ready(function() {
// Initialise the first table (as before)
$("#table-1").tableDnD();
// Make a nice striped effect on the table
$("#table-2 tr:even').addClass('alt')");
// Initialise the second table specifying a dragClass and an onDrop function that will display an alert
$("#table-2").tableDnD({
onDragClass: "myDragClass",
onDrop: function(table, row) {
var rows = table.tBodies[0].rows;
var debugStr = "Row dropped was "+row.id+". New order: ";
for (var i=0; i<rows.length; i++) {
debugStr += rows[i].id+" ";
}
$(#debugArea).html(debugStr);
},
onDragStart: function(table, row) {
$(#debugArea).html("Started dragging row "+row.id);
}
});
});
| 1 | One | |
| 2 | Two | |
| 3 | Three | |
| 4 | Four | |
| 5 | Five | |
| 6 | Six | |
| 7 | Seven | |
| 8 | Eight | |
| 9 | Nine | |
| 10 | Ten | |
| 11 | Eleven | |
| 12 | Twelve | |
| 13 | Thirteen | |
| 14 | Fourteen |
What to do afterwards?
Generally once the user has dropped a row, you need to inform the server of the new order. To do this, we’ve
added a method called serialise(). It takes no parameters but knows the current table from the
context. The method returns a string of the form tableId[]=rowId1&tableId[]=rowId2&tableId[]=rowId3...
You can then use this as part of an Ajax load.
This third table demonstrates calling the serialise function inside onDrop (as shown below). It also
demonstrates the “nodrop” class on row 3 and “nodrag” class on row 5, so you can’t pick up row 5 and
you can’t drop any row on row 3 (but you can drag it).
$('#table-3').tableDnD({
onDrop: function(table, row) {
alert($.tableDnD.serialize());
}
});
Ajax result
Drag and drop in this table to test out serialise and using JQuery.load()
| 1 | One | |
| 2 | Two | |
| 3 | Three (Can’t drop on this row) | |
| 4 | Four | |
| 5 | Five (Can’t drag this row) | |
| 6 | Six |
This table has multiple TBODYs. The functionality isn’t quite working properly. You can only drag the rows inside their
own TBODY, you can’t drag them outside it. Now this might or might not be what you want, but unfortunately if you then drop a row outside its TBODY you get a Javascript error because inserting after a sibling doesn’t work. This will be fixed in the next version. The header rows all have the classes “nodrop” and “nodrag” so that they can’t be dragged or dropped on.
| H1 | H2 | H3 |
|---|---|---|
| 4.1 | One | |
| 4.2 | Two | |
| 4.3 | Three | |
| 4.4 | Four | |
| 4.5 | Five | |
| 4.6 | Six | |
| H1 | H2 | H3 |
| 5.1 | One | |
| 5.2 | Two | |
| 5.3 | Three | |
| 5.4 | Four | |
| 5.5 | Five | |
| 5.6 | Six | |
| H1 | H2 | H3 |
| 6.1 | One | |
| 6.2 | Two | |
| 6.3 | Three | |
| 6.4 | Four | |
| 6.5 | Five | |
| 6.6 | Six |
The following table demonstrates the use of the default regular expression. The rows have IDs of the
form table5-row-1, table5-row-2, etc., but the regular expression is /[^\-]*$/ (this is the same
as used in the NestedSortable plugin for consistency).
This removes everything before and including the last hyphen, so the serialised string just has 1, 2, 3 etc.
You can replace the regular expression by setting the serializeRegexp option, you can also just set it
to null to stop this behaviour.
$('#table-5').tableDnD({
onDrop: function(table, row) {
alert($('#table-5').tableDnDSerialize());
},
dragHandle: "dragHandle"
});
| 1 | One | some text | |
| 2 | Two | some text | |
| 3 | Three | some text | |
| 4 | Four | some text | |
| 5 | Five | some text | |
| 6 | Six | some text |
In fact you will notice that I have also set the dragHandle on this table. This has two effects: firstly only
the cell with the drag handle class is draggable and secondly it doesn’t automatically add the cursor: move
style to the row (or the drag handle cell), so you are responsible for setting up the style as you see fit.
Here I’ve actually added an extra effect which adds a background image to the first cell in the row whenever
you enter it using the jQuery hover function as follows:
$("#table-5 tr").hover(function() {
$(this.cells[0]).addClass('showDragHandle');
}, function() {
$(this.cells[0]).removeClass('showDragHandle');
});
This provides a better visualisation of what you can do to the row and where you need to go to drag it (I hope).
Version History
| 0.2 | 2008-02-20 | First public release |
| 0.3 | 2008-02-27 | Added onDragStart option Made the scroll amount configurable (default is 5 as before) |
| 0.4 | 2008-03-28 | Fixed the scrollAmount so that if you set this to zero then it switches off this functionality Fixed the auto-scrolling in IE6 thanks to Phil Changed the NoDrop attribute to the class “nodrop” (so any row with this class won’t allow dropping) Changed the NoDrag attribute to the class “nodrag” (so any row with this class can’t be dragged) Added support for multiple TBODYs–though it’s still not perfect Added onAllowDrop to allow the developer to customise this behaviour Added a serialize() method to return the order of the rows in a form suitable for POSTing back to the server |
| 0.5 | 2008-07-11 | Now supports having a column as a drag handle (specify a class for the dragHandle option when configuring).
Improved the serialize method to use a default (but also settable in the options) regular expression for generating the serialized string. The default is /[^\-]*$/ which will remove everything before a final hyphen, so item-s1 becomes s1. Added $(‘…’).tableDnDUpdate() to cause the table to update its rows so the drag and drop functionality works if, for example, you’ve added a row. Added $(‘…’).tableDnDSerialize() which allows you to serialize a table from any javascript code. Removed remaining $ and replaced with jQuery so that it should work with Prototype and Scriptaculous |
Tags: Drag & Drop, Javascript, Web
Subscribe to news from Isocra



Many thanks for this plugin – works great!
I also got the same problem when dragging the row over to thead. So here is the little fix I did.
Search for this line:
var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y);
And replace the “if” blog immediately following it with:
if (currentRow) { // Only drop on the same parent as the current one if ($(currentRow).parent().get(0).tagName.toLowerCase() == jQuery.tableDnD.dragObject.parentNode.tagName.toLowerCase() && jQuery.tableDnD.dragObject != currentRow) { // TODO worry about what happens when there are multiple TBODIES if (movingDown) { jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling); } else { jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow); } } }What I did was to put in a check to make sure that user can only drop the row onto the same parent. so by putting all the record rows inside the tbody, we now limit the sorting to that tbody only. So when user attempts to drop the row onto thead, nothing happens.
Hope this helps.
Cheers,
Khoa
forgot to say that this plugin works like a charm, I love it. Thank you
Friends,
This is an excellent tool, but I have a problem I am using this standard method
$ (Document). Ready (function () ( $ ('# Table1'). TableDnD (); ));with this option I can make the changes I need, the problem I have that after having made changes in table1 not find a way to send the new changes to a php script to save those changes in a bd.
If you help me please send the reply to my email, thanks in advance
Hi DenisH,
Thanks for the great plugin
Just sharing my experience when retrieve new order from Database and try ordering rows by new order.
I do development with Asp.Net, and it will be lot of code to generate user controls from code behind.
My rows order that saved to Database is something like “t2,t4,t3,t1,t5,t6,t7,t8,t9,t10″ where t2,t4,etc is each rows id. And here’s how to reorder table from jquery
$(document).ready(function() { if ($("[id$='hdOrderValue']").val() != "") { var words = $("[id$='hdOrderValue']").val(); var $table = $("#myTable"); $.each(words.split(","), function(id, val) { var row = $("#" + val); $table.children("tbody").append(row); }); } });hdOrderValue is Asp.Net Hidden User Control.
Hope this could help who get same problem like me.
Cheers,
Erwin
testing code here remove spaces on tags
for (int i = 0; i < top; ++i) {
vector judy = mary();
TomM use the html “pre” tags around your code to get the box or other wise use the html “code” tag for no box but still code formating (replace quotes with angle brackets of course and end your last tag with a (angle bracket left forward slash TAG angle bracket right)
dont think all of this is supported:
http://www.thunderguy.com/semicolon/wordpress/code-markup-wordpress-plugin/
for (int i = 0; i < top; ++i) {
vector judy = mary();
Hello. Thx for the script. Is there a way to move the complete tbody when i click on a th ?!
On the onDrop eventHandler can I cancel the event propagation and restore the state of the grid to what was? If yes any sample code would be helpful
Was anybody able to figure out how to use this plug-in to drag rows across table?
Thanks.
Sorry, typo above.Please read >>
Was anybody able to figure out how to use this plug-in to drag rows between multiple tables?
Hello.
I match a table.insertRow method with this plug in and want to use it, but will it be impossible?
so i’m stuck on this… i have a gridview and it contains asp:boundfields that contain the data from a stored procedure. now i can get the drag class to work and i can see that my row id’s are being created correctly (adding row ids on row create) but what i can’t figure out how to do is to update the server with my new layout. i would like to update my new layout on the server so that when i export it to excel i will see the new dragged/dropped version. anyone have any ideas on how i can accomplish this? if you need to see any code please let me know. as always i would love to get this working and will keep messing with it but i don’t work with jquery or asp everyday so i’m not quite sure if i missing a step. again, any help would be appreciated. thanks!
Hello.
tag added with table.insertRow of javascript doesn’t become Drag object though it is tableDnD function. When this is very done in Drag to target it, is it good?
i want to create a reset on cancel the ordering.. and make the actually the row that has been dragged back into the place before.. is there any functions to do that.. thanks..
Any body tried to implement DnD inside jScrollPane, I am having trouble on scrolling the jScrollPane div….
Its so complicated for me.
I have a request…
I am trying to implement TableDnD function in .Net Grid Control.
Can anybody please help me ..like how can I implement overlay effect. I want to implement it like netflix dvd queue.
In setting this up inside a web control, it just would not drag and drop. It turned out that ev.target.tagName was a SPAN, rather than a TD. So in the makeDraggable function, I changed:
if (ev.target.tagName == “TD”) to:
if (ev.target.tagName == “TD” || ev.target.tagName == “SPAN”)
and all’s well.
Cheers.
This is an excellent tutorial. It works fine for table with static rows. Can you please help me how to implement on table rows created dynamically.
Hi,
This is very good.But is there any plug-in that give feature to drag any item from list box and drop into tree view in asp.net.If yes please let me know .
thanks
can use this example to imganes? or only for tables???