Reputation: 567
I have a basic HTML table, with jQuery's sortable enabled to sort the table rows. (Codepen for the table; code is below)
My ultimate goal, is to be able to allow the user to drag/drop both rows and/or columns if they'd like. I am aware of the connectWith option which can be passed to sortable, but it seems to make all individual td cells moveable - I only want this to apply to entire columns or entire rows (not the individual cells).
I've had a look at jQuery-ui's sortable API documentation, but I am having a difficult time figuring out how this works; I am unsure if the basic sortable class can handle a scenario like this, or if I will need to construct some outside javascript to make this happen.
If I need to use my own javascript, that's not an issue - the problem is, I don't even know where to start (would it be something handled by event listeners?). I am not looking for someone to solve the problem for me - but curious if anyone knows if this sort of thing is possible with the basic sortable class, and if not (if I will need to construct my own js to do this), can you point me in the right direction on where to start, as I really am unsure.
Table HTML:
<table class="mytable">
<caption>My Table</caption>
<tr>
<td id="corner"></td>
<th scope="col">Col I</th>
<th scope="col">Col .II</th>
<th scope="col">Col .III</th>
</tr>
<tr class="sortme">
<th scope="row">Row I</th>
<td>Open</td>
<td>Open</td>
<td>Open</td>
</tr>
<tr class="sortme">
<th scope="row">Row II</th>
<td>Open</td>
<td>Open</td>
<td>Closed</td>
</tr>
<tr class="sortme">
<th scope="row">Row III</th>
<td>Open</td>
<td>Open</td>
<td>Closed</td>
</tr>
</table>
jquery:
$(function() {
$( "tbody" )
.sortable({items: "tr.sortme" });
});
EDIT: I have solved this with DataTables. It will do both row and column reordering simultaneous. (Working codepen.) The usage was incredibly simple. Read the basic installation instructions to find out what scripts you need, download them (make sure to check 'ColReorder' and 'RowReorder' under the 'extensions' section)and then initialize your table as follows:
<script>
$(document).ready( function () {
$('#myTable').DataTable({
searching: false,
ordering: false,
rowReorder: true,
colReorder: true,
});
});
</script>
It was that simple. Note, I have given the 'searching' and 'ordering' options as false because I don't want those features in the table in my situation - you do not need to supply those, and you might find those features useful.
Something important to keep in mind: The HTML posted above will not work with DataTables. There are 2 problems with it. (1) Using tags within the rows (as row labels, or example where I'd written <th scope="row">Row III</th>
) will not work. Instead, I turned those to tags, then it worked. (2) Additionally, your table must have a <thead>
and <tbody>
for DataTables to work (See this section of the install guide which mentions that.).
Finally, I'd like to mention that I've found it useful to provide the following option when initializing DataTables:
rowReorder: {
update: false
},
Apparently, the 'update' option can cause some undesirable behavior for certain tables. For my simple table, I noticed that unless I set this as false, I could only move the rows up and down by one row, no matter how far I dragged it. Setting it as false fixed that issue without causing any issues.
Upvotes: 0
Views: 8309
Reputation: 30893
Consider the following.
$(function() {
function moveColumn(table, sourceIndex, targetIndex) {
console.log("Move Col " + sourceIndex + " to " + targetIndex);
var body = $("tbody", table);
$("tr", body).each(function(i, row) {
$("td", row).eq(sourceIndex).insertAfter($("td", row).eq(targetIndex - 1));
});
}
$(".mytable > thead > tr").sortable({
items: "> th.sortme",
start: function(event, ui) {
ui.item.data("source", ui.item.index());
},
update: function(event, ui) {
moveColumn($(this).closest("table"), ui.item.data("source"), ui.item.index());
$(".mytable > tbody").sortable("refresh");
}
});
$(".mytable > tbody").sortable({
items: "> tr.sortme"
});
});
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.0/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.0/jquery-ui.js"></script>
<table class="mytable">
<caption>My Table</caption>
<thead>
<tr>
<td id="corner"></td>
<th scope="col" class="sortme">Col I</th>
<th scope="col" class="sortme">Col II</th>
<th scope="col" class="sortme">Col III</th>
</tr>
</thead>
<tbody>
<tr class="sortme">
<th scope="row">Row I</th>
<td>Open</td>
<td>Open</td>
<td>Open</td>
</tr>
<tr class="sortme">
<th scope="row">Row II</th>
<td>Open</td>
<td>Open</td>
<td>Closed</td>
</tr>
<tr class="sortme">
<th scope="row">Row III</th>
<td>Open</td>
<td>Open</td>
<td>Closed</td>
</tr>
</tbody>
</table>
This is a basic example. There are some pitfalls, like there is not a good placeholder for the Columns, where the Rows will have one.
Upvotes: 2