JS DataTables ColReorder API Reorder Bug? - javascript

JS DataTables ColReorder results in unexpected behavior when using the API to re-order columns.
https://github.com/DataTables/ColReorder/
A first re-order works fine e.g.
tableColReorder.fnOrder([2, 1, 0]);
But this subsequent re-order should return columns to their original order but it doesn't. Why not?
tableColReorder.fnOrder([0, 1, 2]);
Simple fiddle example here:
http://jsfiddle.net/h7wdt72k/
$(document).ready(function () {
// Initialize data table extension.
var table = $('table')
.DataTable({
paging: false,
searching: false,
ordering: false,
bInfo: false
});
// Initialize column re-order extension.
tableColReorder = new $.fn.dataTable.ColReorder(table);
// Re-order columns. Switch first/last columns.
tableColReorder.fnOrder([2, 1, 0]);
// Re-order columns to original order 0, 1, 2. Does not work!?
tableColReorder.fnOrder([0, 1, 2]);
// Get current column order. Did not apply re-order directly above. Why not!?
alert(tableColReorder.fnOrder());
// This statement returns columns to original order 1, 2, 3. Works but why!?
//tableColReorder.fnOrder([2, 1, 0]);
});
html:
<table border="1">
<thead>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>

Behavior is by design and not a bug.
//To switch position of two columns, always reorder based on array of consecutive integers (array length = number of columns).
//Even if columns already moved. Start with array of consecutive integers.
newColOrder = [0,1,2];
// Set new order of columns.
newColOrder[colTo] = colFrom; // colFrom = index to move column from.
newColOrder[colFrom] = colTo; // colTo = index to move column to.
e.g. to switch first and last column.
newColOrder[0] = 2;
newColOrder[2] = 0;
// [2,1,0];
// Reorder columns. Switch position of first and last column.
tableColReorder.fnOrder(newColOrder);
// Switch position of first and last column again. Returns columns to original position.
tableColReorder.fnOrder(newColOrder);

Related

Permanently reverse the order of a DataTable in jQuery?

Let's say I have a Data Table like so:
<table id="history" class="display">
<thead>
<th>Player</th>
<th>Word</th>
<th>Value</th>
<th>Message</th>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
</tbody>
</table>
I have a function that receives a payload from the server and adds a row to the datatable with the relevant information
var history_data_table = $('#history').DataTable({
"pageLength": 5,
"searching": false,
"bLengthChange": false,
"language": {
"emptyTable": "Words that you discover will appear here."
}
});
function liveRecv(word_payload) {
history_data_table.row.add([word_payload.id_in_group,
word_payload.word,
word_payload.word_value,
word_payload.message]
).draw();
Naturally, this will add the row to the end of a paginated table. This table is a list of transactions in a game, and I want to present the most recent transactions to the user, such that every row that's added is added to the top of the data-table. What is the easiest way to achieve this?
You could try this method using jQuery
$('#history tr:first').after("<tr role="row"><td></td><td>add you own row</td></tr>");
or you could use DataTables inner function to access the array of rows
var history_data_table = $('#history').dataTable();
var DisplayMaster = history_data_table.fnSettings()['aiDisplayMaster'];
var tableapi = history_data_table.api();
var getlastrow = DisplayMaster.pop();
DisplayMaster.unshift(getlastrow);
tableapi.draw(false);

Sort main rows while keeping sub order - jquery

I'm trying to figure out a good way to have a table which has sub data where we can sort on the main table without altering the sub data. Here's a MWE.
<table id="my-table">
<tr>
<th>Name</th>
<th class="selectable">Num</th>
</tr>
<tr id="main-1" class="main">
<td>Main 1</td>
<td>1</td>
</tr>
<tr class="main-1 sub">
<td>Sub 1</td>
<td>3</td>
</tr>
<tr id="main-2" class="main">
<td>Main 2</td>
<td>2</td>
</tr>
<tr class="main-2 sub">
<td>Sub 2</td>
<td>4</td>
</tr>
</table>
So you can kind of see I have 4 rows altogether, 2 rows that are "main" rows and 2 that are "sub" rows which are associated to certain "main" rows as can be seen through their classes.
What I'm looking to do is sort the table in such a way that only the main rows get sorted and the sub rows travel with the main rows. So if I sort by the second column I would have Main 1 - Sub 1 - Main 2 - Sub 2 and if I reverse the sort I would have the order Main 2 - Sub 2 - Main 1 - Sub 1.
I tried using https://github.com/padolsey-archive/jquery.fn/tree/master/sortElements but this seems to do the entire table and I can't figure out how to make it move "groups" of rows together.
Any ideas?
(Note: the reason I'm doing the HTML structure as is, is because normally all ".sub" are hidden and when you click on ".main" it grabs the id and shows everything that has a class with that id. I'm open to changing the HTML structure if needed, and I don't mind either way if the sub elements get sorted too, I just prefer that they move with the main row)
This is the code I was using, but since it only does every line in the table, it's not really relevant:
$('.sub').toggle();
$('.main').on('click', function(e) {
e.preventDefault();
$('.' + $(this).attr('id')).toggle();
});
var table = $('#my-table');
$('th.selectable')
.wrapInner('<span title="sort this column"/>')
.each(function(){
var th = $(this),
thIndex = th.index(),
inverse = true;
th.click(function(){
table.find('td').filter(function(){
return $(this).index() === thIndex;
}).sortElements(function(a,b){
a_num = parseInt($.text([a]))
b_num = parseInt($.text([b]))
if (a_num == b_num)
return 0;
return a_num > b_num ?
inverse ? -1 : 1
: inverse ? 1 : -1;
}, function() {
// parentNode is the element we want to move
return this.parentNode;
});
inverse = !inverse;
});
});

Jquery sort of table -> Numbers before text

I am working on a wait times API to show the current queuing times of the Disney-parks.
The wait times are loaded in a table in alphabetical order.
Now I have used the following code to sort this table on highest waits on top of the table to the lowest waits. That is what I want:
$(document).ready(function(){
var sorted = $('#mytable tbody tr').sort(function(b, a) {
var a = $(a).find('td:last').text(), b = $(b).find('td:last').text();
return a.localeCompare(b, false, {numeric: true})
})
$('#mytable tbody').html(sorted)
});
This works great, BUT as you can see in the image below the text values like 'Closed' and 'Refurbishment' are on top of the table, above the highest wait time.
How can I change this order of the table to get the highest wait times on top of the table and at last the text-values?
Current order, want to change this
So I want to get:
20 min.
15 min.
5 min.
Open
Closed
Refurbishment
To sort as you require, you need to sort differently dependent on whether the value is numeric or not. If both are numeric, compare as you currently do. Otherwise, if only one is numeric, sort that to the beginning; and if both are not numeric, sort according to your required order (Open, Closed, Refurbishment), which can be implemented by looking up the phrase in an object that defines the sort order:
var states = {
'Open': 0,
'Closed': 1,
'Refurbishment': 2
};
$(document).ready(function() {
var sorted = $('#mytable tbody tr').sort(function(b, a) {
var a = $(a).find('td:last').text(),
b = $(b).find('td:last').text();
if (!isNaN(parseInt(a))) {
if (!isNaN(parseInt(b))) {
// a and b both numeric
return a.localeCompare(b, false, {
numeric: true
});
} else {
// a numeric, b not, sort b last
return 1;
}
} else if (!isNaN(parseInt(b))) {
// a not numeric, b numeric, sort a last
return -1;
} else {
// a not numeric, b not numeric, sort regular
return states[b] - states[a];
}
});
$('#mytable tbody').html(sorted)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="mytable">
<tbody>
<tr>
<td>Challenge trails</td>
<td>Refurbishment</td>
</tr>
<tr>
<td>Camp Discovery</td>
<td>Open</td>
</tr>
<tr>
<td>Soaring</td>
<td>120 mins</td>
</tr>
<tr>
<td>Fantasia</td>
<td>20 mins</td>
</tr>
<tr>
<td>Shipwreck Shore</td>
<td>5 mins</td>
</tr>
<tr>
<td>Rex's Racer</td>
<td>105 mins</td>
</tr>
<tr>
<td>Slinky Dog</td>
<td>Closed</td>
</tr>
</tbody>
</table>

Applying fnFilter to a modified table

Using DataTables 1.9.4 and JQuery 1.4.4.
I'm trying to create a table which filters certain rows based on the visible column. The table is driven by an AngularJS like in-house controller.
When the table is displayed, the filter works fine, but thereafter, if the value changes, the filter is not updated.
The controller consists of an array (one for each row). When the table is updated through it, the filter is not reapplied. How can I make the filter reevaluate each row when the data changes?
HTML as generated by controller:
<table id="table-status">
<thead>
<tr>
<th>visible</th>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>name1</td>
<td>1</td>
</tr>
<tr>
<td>0</td>
<td>name2</td>
<td>2</td>
</tr>
<tr>
<td>1</td>
<td>name3</td>
<td>3</td>
</tr>
</tbody>
</table>
The DataTables initialization:
var oTable = $("#table-status").dataTable( {
"aoColumnDefs": [ { "bVisible": false, "aTargets": [ 0 ] },
{ "bVisible": true, "aTargets": [ 1 ] },
{ "bVisible": true, "aTargets": [ 2 ] } ],
"bSort": false,
"bFilter": true
} );
oTable.fnFilter("1", 0, false, false, false, false);
I'm not entirely sure if this is what you need, but I rolled my own function to display or not some rows, based on a column called Status.
I have a checkbox that can contain the values 0, 1, 2 and 3.
First, I get the regex function associating the values I want to filter:
var filter = "^" + $("#filterStatusCheck option:selected").map(function() {
return this.value;
}).get().join("|") + "$";
Which returns, for instance, ^1|2$, meaning I want to filter the values 1 and 2.
Then, I search() the DataTable, looking for those elements (not me, actually, but rather their search() method.
var t = s.getTable().DataTable();
t.column(8).search(filter, true, false).draw();
Here, on column with the index of 8, I'm doing so that it searches, using the above filter, and then draw() the DataTable again.
In your case, you might want to figure out what event you can attach the above code (maybe right after the row has been updated?). Your filter would be 1 (visible, right?), whereas your column search would be 0 (the first column called visible).
Hope it helps.

Retrieve data attribute of a selector class as an array

I am running a PHP + JQuery + DataTables page. Everything went fine and I have a similar mark up from the following:
.......
<tbody>
<tr data='1'>
....
</tr>
<tr data='2'>
....
</tr>
<tr data='1'>
....
</tr>
<tr data='8'>
....
</tr>
<tr data='2'>
....
</tr>
<tr data='7'>
....
</tr>
<tr data='7'>
....
</tr>
.
.
.
</tbody>
I need to get all the data attribute of all the tr in an array, well in the case of the above table, its:
var data_values = [1, 2, 8, 7];
I think that the logic may somewhat starts with $('tr').attr('data') but it returns undefined. I've performed already a query to the database and it also returns an array:
var database_returned_values = [2, 8];
My goal from the start is to remove the tr elements that are not found in the database_returned_values array. My solution is to subtract database_returned_values array from data_values. The difference will be the trs to remove. But I cannot even start to fetch data_values. How can I retrieve the data attributes of all tr and put it in an array or are there any easier way to do this?
In this case, the trs to remove are those which have data attribute of [1, 7];
You can use each() to iterate all the tr:
var data = new Array();
$("table tbody tr").each(function(){
if($.inArray($(this).attr("data")) == -1) // check if not in array
data.push($(this).attr("data"))
})
The data property needs to have something after it.
<tr data-id='7'>
And then jQuery has a nice method you can use called data.
$("tr").data("id")
You can get all the trs, then iterate them. Then, you have to read the data-* attribute (you should'n use only data="anything") and add to an empty array. Then, remove duplicates.
As long as you are using jQuery, you can do this with:
<table>
<tr data-id="1"></tr>
<tr data-id="3"></tr>
<tr data-id="1"></tr>
<tr data-id="4"></tr>
<tr data-id="4"></tr>
<tr data-id="7"></tr>
</table>
var ids = [];
$("table tr").each(function(index, item) {
ids.push($(item).data("id"));
})
alert($.unique(ids));
Fiddle: http://jsfiddle.net/chrisbenseler/s8pytwdz/
Then, iterate this new array ($.unique(ids)) and check whatever you need to check.

Categories

Resources