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.7).
- 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 using
onDragClass.) 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 is
tDnD_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).
880 Responses to Table Drag and Drop JQuery plugin
Leave a Reply Cancel reply
If you enjoyed reading or using this, please consider donating
Tags
ADSI Architecture C++ CSS CUPS databases Debugging design Drag & Drop EEE PC Entourage Firefox free tools Graphs Groovy Hardware Hibernate HTML Internationalisation Internet Explorer Java Javascript JNI JSP LDAP Lisp Localisation Mac MacBook Mac OS X Mail Mobile Broadband MySQL Occam Operating Systems Parallels Persistence printing requirements Rules security UTF8 Web Web development Windows







Nino printed some work back in 08 on how to use with scrollable div. Seems (prob due to cut-n-paste issues) to be problematic. does anyone have this effort functional? New (sadly) to all this javascript/jquery so I’m weak and learning but need to use something like this
Any help appreciated – Thanks!
Hi
very nice script
can anybody help on the following senerio
i am having one html table inside the div and i am trying to drag the rows its working for me but the vertical div scroll is not working if the selected ro dragged at the end of the div
please give me any solution
thanks
irfan
Good stuff.
To drag only when using the left button, insert
if (ev.which != 1) { return false; }at the beginnig of the two
.mousedown(function(ev) { (...)handlers.the which property is provided by jQuery, so no need to worry about compat.
Also, since “dragObject” is not assigned, there is no need to modify the *move and *up events.
very good
but i want to drag and drop / and then to vote … i can do this ?
i want this for an top 20 music
you can help me pls ?
Hi guys,
Thanks for this great script !
I need to implement a sortable list (with drag n’ drop). It works fine.. but I need to use pagination to navigate through the list.
Do someone have an idea on how to implement this drag n’drop script with a pagination ?
Many thanks,
Chris
I know that people have been asking for a while how to drag table bodies, instead of just individual rows. I needed this functionality for a project, so I spent some time figuring out how to implement the solution.
It turns out that this requires relatively minor changes to the script. By changing the two lines below, you can drag table bodies just as you drag rows. If you use this solution, you will have to enclose even individual rows in tags. However, the nice part is that you can drag multiple rows as if they were a single row.
line 130: jQuery.tableDnD.dragObject = this.parentNode.parentNode;
line 285: var rows = jQuery.tableDnD.currentTable.tBodies;
[...] Table drag and drop jQuery plugin – Link. [...]
Can anyone suggest me how to drag multiple rows?
Hi Jon Can you please provide me the script you used for dragging and dropping multiple rows
Hi Rocky,
The solution I posted should work for you, if you are using the version of tablednd from this site.
You will need to enclose individual rows in tags, in addition to enclosing multiple sets of rows.
So for example:
row-one
row-two
row-three
Let me know if it is still not working, and I can paste the complete script. However, I only made the two changes above.
I think I see the problem….my code only works if you use a drag handle. I will have to make another tweak in another place if you aren’t using a draghandle. Let me know if this is what you need.
Excellent script. Was initially confused that there are two versions of the script – one for use with jQuery, and one without. This explained the “tableDnD is not a function” error message I was getting when trying to use the non-jQuery version…
Jon – Thanks for your tweaks to enable the selction of multiple rows using the Drag Handle. You mentioned that it could work without the use of the Drag Handle. Would you be so kind as to show us to make it work without the use of the drag handle?
Thanks!
Thank You for this precious litte tool. Helped a lot
Cool script. Love it.
I want to be able to use your script to nest rows under their parent rows. Is this possible?
Example:
row1
row2
row2.1
row2.2
row3
row4
row4.1
row4.2
row5
Hi Jon Can u please post the script?
Appreciate your help.
Have a Great day
Here is a link to my script.
http://www.878282v6y7k.com/dev/
I would like to be able to nest rows under their parent rows. Something like this.
[drag] Sports 2 Yes
—[drag] Golf 2 Yes
—[drag] Football 2 Yes
—[drag] Baseball 2 Yes
[drag] Tech 2 Yes
—[drag] Mobile 2 Yes
If you change line 142 to:
var rows = jQuery(“tbody”, table); // get all the rows as a wrapped set
…that should work to drag tbodies with any td. You will also have to make this change I posted earlier to line 285:
var rows = jQuery.tableDnD.currentTable.tBodies;
That should work for dragging tbodies when draghandle is not specified. I haven’t had time to test this thoroughly…so there might be bugs. I have done most of my work with the drag handle functionality enabled.
Hope that helps. Let me know if there are problems.
Any news on dragging between tables?
With two tables (left and right) I can implement something like ‘available’ and ‘selected’ by dragging rows from left to right table and sorting the selected items by dragging a row up and down in the richt table
Best Table Drag And Drap j query Table code It will be useful For My New Web site.
Hi
I want to drag drop rows between two tables
Can this possible.
If yes please send me th code
Thanks for nice script, but i want the swaping of rows, means if the inicially the arrangement is
r1
r2
r3
r4
then
if i drag r4 to r1 then the arrangement will be
r4
r2
r3
r1
Hey Everyone,
First of all, I’d like to give props to DenisH for the great plug-in! It really saved my a lot of time on a Form Builder project I’ve been working on recently. I am, however, disappointed to see that development on TableDnD seems to have come to a halt, but I know how it is maintaining free software — a thankless job to some degree.
Anyway, the main reason I’m posting is to share a minor modification I made to your script. After I coded this “hack” (which took only about 20 minutes, thanks to your fantastic API), I realized that it’s not that uncommon a need, and that other developers might be wishing there was a similar feature implemented.
Basically, I needed to prevent the onDragStart callback from being called just because of a quick, single click on a drag-able row. What I mean is, I didn’t want my onDragStart callback being called when the user was just CLICKING on the row, and NOT trying to actually drag the row around. In the Form Builder script I’m developing, the onDragStart callback causes the inline “Edit Question” form to be hidden, which is required if your dragging a row — but just irritating if you don’t intend to actually drag it. So basically, this little mod just makes the script a little more intuitive (IMO), and helps to determine what the users intent was (to drag, or simply click?).
To implement this, I modified the makeDraggable method in the plug-in itself. Inside the conditional that checks to see if an onDragStart callback is specified, I added a few lines. First the mouse offset position (Y cord only) is stored when the dragCell is initially clicked. Then, bind a callback to the “mousemove” event on the dragCell element. When mousemove fires, I simply get the new mouse offset Y cord, then check to see if it’s changed (increased or decreased) by at least 2 pixels (you could easily change it to however many pixels). If it has, the onDragStart callback is called, otherwise it’s not. In either case, I DO clean-up by unbinding the mousemove callback.
I hope someone may find this snippet helpful. I thought it was a useful little enhancement. Please do note, the code I’ve included ONLY works if your using a dragCell (not the entire row). However, one could easily take my code snippet and move it into the else statement a few lines below which is for those not using a dragCell. I just didn’t need that.
If anyone needs some help with this, feel free to drop me a line at snconners@gmx.co.uk, as I don’t frequent DenisH’s blog often.
————–
Grab TableDnD v0.5 with my mod here: http://pastebin.com/f31a6ee99
Or, here’s just the modified code itself, starting around line 146 of v0.5:
jQuery(this).mousedown(function(ev)
{
jQuery.tableDnD.dragObject = this.parentNode;
jQuery.tableDnD.currentTable = table;
jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev);
/*
** Only call onDragStart if
** mouse moves > 2px (on Y)
*/
if(config.onDragStart)
{
var startOffset = jQuery.tableDnD.mouseOffset.y;
jQuery(this).bind(“mousemove”, function(ev)
{
var newOffset = jQuery.tableDnD.getMouseOffset(this, ev).y;
if(newOffset > startOffset + 2 || newOffset < startOffset – 2)
{
config.onDragStart(table, this); // Call onDragStart callback
}
});
}
return false;
});
i have just used the table DND and saved sort-list in cookies. That means the sor-list can be reloaded on table-sort initing later.
The sort-function can be inserted in build block of tableDnD main codes.
$(document).ready(function() { // Initialise the table $(".tbl").tableDnD({ onDragClass: "myDragClass", onDrop: function(table, row) { var rows = table.tBodies[0].rows; var orderStr = ""; for (var i = 0; i < rows.length; i++) { orderStr += rows[i].id + ";"; } $(".test").html(orderStr); $.cookie("order_"+ $(".plabel").text(), orderStr, { expires: 30}); }, containerDiv: $("#viewContent") }); $(".test").html($.cookie("order_"+ $(".plabel").text())); });Hallo Nino Dafonte,
your codes of “TableDnd in Scrolled Div” have a bug, that the scroll can only be scrolled down. Scroll up is not working . The codes shuld be changed like so:
var container = config.containerDiv; var yOffset = container.scrollTop(); var windowHeight = container.innerHeight(); var y = mousePos.y - jQuery.tableDnD.mouseOffset.y; var upperBorder = container.position().top + container.innerHeight(); // not error, it should also be added because mouse moves up var bottomBorder = container.position().top + container.innerHeight(); if (mousePos.y > bottomBorder) { container.scrollTop(container.scrollTop() + config.scrollAmount); } if (mousePos.y < upperBorder) { container.scrollTop(container.scrollTop() - config.scrollAmount); }It is possible now drag and drop under parent rows?
Thanks.
Great script! Do you have any plan to add drag/drop column instead of row?
I have a problem with this plugin when using dragHandle.
If you stay with the cursor with mousedown just between 2 td’s the drag image will appear on both.
It’s very annoying. :/
Anyone could help me fix it? I’ve tried alot and I don’t think this plugin will be updated anymore, right?
Thanks
Also, I can’t get tableDnDUpdate() working ;/
I was able to get the multi-tbody functionality working with a little effort:
Modify code near line 270:
if (currentRow) { // same tbody if (jQuery.tableDnD.dragObject.parentNode == currentRow.parentNode) { // make sure we've moved if (jQuery.tableDnD.dragObject != currentRow) { if (movingDown) jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling); else if ( !movingDown) jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow); } } // different tbody else { var tmpObject = jQuery(jQuery.tableDnD.dragObject).detach(); if (movingDown) tmpObject.insertBefore(jQuery(currentRow)); else if ( !movingDown) tmpObject.insertAfter(jQuery(currentRow)); } }Note: requires jquery 1.4! (the detach() method makes the magic happen…)
Regards,
Landon
[...] 7. Table row drag and drop 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. [...]