The idea is pretty simple and it almost works. There are two tables and the user has the option of dragging rows between the two tables. When a row is dragged from table1 to table2, ajax is used in order to update the database with the data that is removed from table1, added to table2, and to re-display both of the tables with the new data. The same thing works if information is dragged from table2 to table1.
You can see a sample of the code here.
Here is an excerpt of the Javascript code for one of the tables:
var startTable = "table1";
var $tabs=$("#" + startTable);
$( "tbody.connectedSortable")
.sortable({
connectWith: ".connectedSortable",
items: "> tr:not(:first)",
appendTo: $tabs,
helper:"clone",
cursor:"move",
zIndex: 999990
})
.disableSelection()
;
$($tabs).droppable({
accept: ".connectedSortable tr",
hoverClass: "ui-state-hover",
drop:function(event, ui){
var start= ui.draggable.attr("id");
var desTable = $(this).attr("id");
if(start != desTable){
alert("The ajax should be called");
}
return false;
}
});
It works perfectly except for just one case. If a row is being dragged from Table1 to Table2, it creates a slot to show where the row will be inserted when the row is let go. In other words, if a user drags a row from Table1 to the last element of Table2, it creates an open place-holder (under the last row in Table2) to depict where the row will go when let go. There is one problem with this. If the place-holder is created but the row is then dragged outside of the table and let go, the row still goes to the place-holder but the draggable property is never called.
What I would like to happen is if a place-holder is created, no matter where the row is let go, it will go to the place-holder and call the droppable code that corresponds to the table it was dropped in. If no place-holder is present, the row should go back to where it was dragged from and nothing should happen.
Every example I've tried that drags rows between two tables has the same problem. Do you guys have any way to call the droppable code even if the row is being dropped outside of the table? Or maybe there is a better way to call ajax rather than when the row is dropped on the table? Any insight would be greatly appreciated.
The idea is pretty simple and it almost works. There are two tables and the user has the option of dragging rows between the two tables. When a row is dragged from table1 to table2, ajax is used in order to update the database with the data that is removed from table1, added to table2, and to re-display both of the tables with the new data. The same thing works if information is dragged from table2 to table1.
You can see a sample of the code here.
Here is an excerpt of the Javascript code for one of the tables:
var startTable = "table1";
var $tabs=$("#" + startTable);
$( "tbody.connectedSortable")
.sortable({
connectWith: ".connectedSortable",
items: "> tr:not(:first)",
appendTo: $tabs,
helper:"clone",
cursor:"move",
zIndex: 999990
})
.disableSelection()
;
$($tabs).droppable({
accept: ".connectedSortable tr",
hoverClass: "ui-state-hover",
drop:function(event, ui){
var start= ui.draggable.attr("id");
var desTable = $(this).attr("id");
if(start != desTable){
alert("The ajax should be called");
}
return false;
}
});
It works perfectly except for just one case. If a row is being dragged from Table1 to Table2, it creates a slot to show where the row will be inserted when the row is let go. In other words, if a user drags a row from Table1 to the last element of Table2, it creates an open place-holder (under the last row in Table2) to depict where the row will go when let go. There is one problem with this. If the place-holder is created but the row is then dragged outside of the table and let go, the row still goes to the place-holder but the draggable property is never called.
What I would like to happen is if a place-holder is created, no matter where the row is let go, it will go to the place-holder and call the droppable code that corresponds to the table it was dropped in. If no place-holder is present, the row should go back to where it was dragged from and nothing should happen.
Every example I've tried that drags rows between two tables has the same problem. Do you guys have any way to call the droppable code even if the row is being dropped outside of the table? Or maybe there is a better way to call ajax rather than when the row is dropped on the table? Any insight would be greatly appreciated.
Share Improve this question edited Nov 23, 2014 at 20:01 Brian asked Nov 20, 2014 at 20:04 BrianBrian 5292 gold badges7 silver badges17 bronze badges 4- you could use the update event in sortable instead of the drop event. – Parthik Gosar Commented Nov 23, 2014 at 18:24
- It would be amazing if it is that simple. I'll be working on it in about an hour and will post back the results then. Thanks. – Brian Commented Nov 23, 2014 at 18:40
- The update event looks like what I'm looking for. I changed my code to use update but I ran into a bug. The update from table1 is never called, only update from table2 is called. Also, if I drag from table1 to table2, the table2 update is called twice. Here's the fiddle: jsfiddle/bhealy/t011juda/28 Any idea what's going on? – Brian Commented Nov 23, 2014 at 19:42
- You are applying the sortable function on the same identifier ($("tbody.connectedSortable")) twice. One should be for table1 and the other should be for table2. Check this fiddle jsfiddle/t011juda/35 – Parthik Gosar Commented Nov 23, 2014 at 22:03
2 Answers
Reset to default 10 +50For triggering an ajax request when a row is dropped from one table to another you can use the receive event of sortable
widget.
This event is triggered when an item from a connected sortable list has been dropped into another list. The latter is the event target.
(emphasis mine)
Updated Fiddle (Partial result, See the below snippet for final demo)
Inside the receive callback, you can access the dropped row using the item
property of second argument (ui.item
).
If the receive event callback is triggered, it means ui.item
has been added to this
table ($(this).closest("table.mytable")
) and removed from the other table ( $("table.mytable").not($(this).closest("table.mytable"))
). You can then trigger the ajax request(s) accordingly.
By doing it this way, you don't have to manually check whether drop happened within the same table or not (You'll have to do this if you're using update event as someone suggested).
At the moment, you're unnecessarily initializing the sortable twice with:
$( "tbody.connectedSortable").sortable({
connectWith: ".connectedSortable",
items: "> tr:not(:first)",
appendTo: $tabs,
helper:"clone",
cursor:"move",
zIndex: 999990
})
and
$("tbody.connectedSortable").sortable({
connectWith: ".connectedSortable",
items: "> tr:not(:first)",
appendTo: $tabs2,
helper:"clone",
cursor:"move",
zIndex: 999990
});
The selector tbody.connectedSortable
is applicable to both tables, hence it'll simply override the previous initialization, As the result, the clone helper will be always appended to the second table ($tabs2
). It is probably not what you want - from the looks of it you're initializing twice just for appending the clone to respective parent. The default value of appendTo
option is "parent"
, just removing it from initialization will do the job.
Also, it is a good idea to move the header rows from <tbody>
into <thead>
element so that you can avoid specifying items: "> tr:not(:first)"
: it is more semantic as well as slightly better for performance since jQuery UI doesn't have to search for invalid items if that option is not specified.
Finally, you've duplicate id
's which is invalid. For grouping a set of elements, use a mon class instead.
$(document).ready(function() {
$("tbody.connectedSortable").sortable({
connectWith: ".connectedSortable",
helper: "clone",
cursor: "move",
zIndex: 99999,
receive: function(event, ui) {
/* here you can access the dragged row via ui.item
ui.item has been removed from the other table, and added to "this" table
*/
var addedTo = $(this).closest("table.mytable"),
removedFrom = $("table.mytable").not(addedTo);
alert("The ajax should be called for adding to " + addedTo.attr("id") + " and removing from " + removedFrom.attr("id"));
}
});
});
.mytable a:link,
.mytable a:visited {
color: #fff;
font-weight: bold;
text-decoration: none;
}
.mytable a:active,
.mytable a:hover {
color: #bd5a35;
text-decoration: underline;
}
table.mytable {
width: 90%;
font-family: Arial, Helvetica, sans-serif;
color: #666;
margin-left: auto;
margin-right: auto;
font-size: 12px;
background: #eaebec;
border: #ccc 1px solid;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-box-shadow: 10px 10px 5px #888;
-webkit-box-shadow: 10px 10px 5px #888;
box-shadow: 10px 10px 5px #888;
}
.mytable th {
color: #fff;
padding: 21px 25px 22px 25px;
border-top: 1px solid #fafafa;
border-bottom: 1px solid #e0e0e0;
background: #191970;
}
.mytable th:first-child {
text-align: center;
padding-left: 20px;
}
.mytable tr {
text-align: center;
padding-left: 20px;
}
.mytable tr td:first-child {
text-align: center;
padding-left: 20px;
border-left: 0;
}
.mytable tr td {
padding: 18px;
border-top: 1px solid #ffffff;
border-bottom: 1px solid #e0e0e0;
border-left: 1px solid #e0e0e0;
background: #fafafa;
background: -webkit-gradient(linear, left top, left bottom, from(#fbfbfb), to(#fafa fa));
background: -moz-linear-gradient(top, #fbfbfb, #fafafa);
}
.mytable tr.even td {
background: #f6f6f6;
background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#f6f6 f6));
background: -moz-linear-gradient(top, #f8f8f8, #f6f6f6);
}
.mytable tr:last-child td {
border-bottom: 0;
}
.mytable tr:last-child td:first-child {
-moz-border-radius-bottom-left: 3px;
-webkit-border-bottom-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.mytable tr:last-child td:last-child {
-moz-border-radius-bottom-right: 3px;
-webkit-border-bottom-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.mytable tr:hover td {
background: #f2f2f2;
transform: scale(1.01);
padding-left: 20px;
outline: 1px solid #191970;
-moz-box-shadow: 10px 10px 5px #888;
-webkit-box-shadow: 10px 10px 5px #888;
box-shadow: 10px 10px 5px #888;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.jquery./ui/1.9.2/jquery-ui.js"></script>
<table id='table1' class="mytable">
<thead>
<tr class="table1">
<th>col1</th>
<th>col2</th>
<th>col3</th>
<th>col4</th>
</tr>
</thead>
<tbody class="connectedSortable">
<tr class="table1">
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
</tr>
<tr class="table1">
<td>e</td>
<td>f</td>
<td>g</td>
<td>h</td>
</tr>
</tbody>
</table>
<table id='table2' class="mytable">
<thead>
<tr class="table2">
<th>COL1</th>
<th>COL2</th>
<th>COL3</th>
<th>COL4</th>
</tr>
</thead>
<tbody class="connectedSortable">
<tr class="table2">
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr class="table2">
<td>5</td>
<td>6</td>
<td>7</td>
<td>8</td>
</tr>
</tbody>
</table>
Side note: I've bined the similar CSS classes
The disableselection() method is deprecated from jQuery UI
1.9+
I think this fiddle gives you what you want: http://jsfiddle/t011juda/31/
$(document).ready(function () {
var startTable = "table1";
var $tabs = $("#" + startTable);
$("tbody.connectedSortable")
.sortable({
connectWith: ".connectedSortable",
items: "> tr:not(:first)",
appendTo: $tabs,
helper: "clone",
cursor: "move",
zIndex: 999990,
start: function (event, ui) {
//alert("start1");
var start_pos = ui.item.index();
ui.item.data('start_pos', start_pos);
}
});
var startTable2 = "table2";
var $tabs2 = $("#" + startTable2);
$("tbody.connectedSortable")
.sortable({
connectWith: ".connectedSortable",
items: "> tr:not(:first)",
appendTo: $tabs,
helper: "clone",
cursor: "move",
zIndex: 999990,
start: function (event, ui) {
//alert("start2");
var start_pos = ui.item.index();
ui.item.data('start_pos', start_pos);
//alert(start_pos);
},
update: function (event, ui) {
if (this.id == 'table2' && this === ui.item.parent()[0] )
alert("update2");
else if (this.id == 'table1' && this === ui.item.parent()[0] )
alert("update1");
}
});
});
Actually, the explanation for list updated twice is given here: jquery Sortable connectWith calls the update method twice
Note that you had table1
and table2
ids repeated.I have removed the duplicates and moved one of them onto <tbody>
.
Note also that `update handles D&D both ways