'jquery datatables column visibility buttons bug with column reorder? Button marked as "noVis" shows up anytime the columns are put in original order
I have a rails app that uses bootstrap 4, jquery, and jquery datatables. I am using the column-reorder plugin, and the column visibility plugin. Everything is working, but I have a column that is checkboxes, so I want to exclude it from the column visibilty toggle list. I do this with the recommended code that applies a class of "noVis" to the target column. The problem is when the table loads the checkbox column is visible in the list of buttons as a thin line (since the column has no text in the header) but if I reorder any of the columns, the button that should be invisible goes away. If I put the columns into any order and navigate away from the page, when I come back the button for the checkbox column will still be invisible. But if I put the columns back into their original order and refresh the page, the checkbox button shows up again. It's driving me crazy as the jquery code is pretty much a black box so I can't see what's happening inside.
javascript:
<script>
function getParam()
{
return decodeURI(window.location.href.slice(window.location.href.indexOf('?') + 1).split('=')[1]);
}
$.fn.dataTable.ext.order['dom-checkbox'] = function ( settings, col )
{
return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
return $('input', td).prop('checked') ? '0' : '1';
} );
};
$('#user_table').DataTable( {
stateSave: true,
stateDuration: 0,
dom: '<"toolbar">Bfrtip',
colReorder: true,
buttons: [
{ extend: 'colvis', position: 'dropdown', columns: ':not(.noVis)',
className: "btn btn-xs btn-brand dropdown-toggle", dataToggle: "dropdown", ariaExpanded: "false"},
{ extend: 'copy', className: 'btn btn-xs btn-brand' },
{ extend: 'print', className: 'btn btn-xs btn-brand' },
{ extend: 'csv', className: 'btn btn-xs btn-brand' },
{ extend: 'excel', className: 'btn btn-xs btn-brand' }
],
inputType: 'search',
"columnDefs": [
{ "searchable": false, "targets": [5,6] },
{"targets": [0], "orderDataType": "dom-checkbox"},
{"targets": [0,5,6], "className": "noVis"}
],
"oLanguage": {
"sSearch": "Filter: "
},
search: {
search: '<%= raw(@filter) %>'
},
scrollY: 550,
scrollX: true,
scrollCollapse: true,
paging: false,
fixedHeader: {
header: true,
footer: true
},
"initComplete": function(settings, json) {
if (getParam() !== 'undefined') {this.api().search(getParam()).draw();}
}
} );
$(document).on('turbolinks:load', function() {
$(".tag").click(function () {
let title = $(this).attr('value');
console.log("clicked tag")
console.log(title)
$('#user_table').DataTable().search(title).draw();
return false;
});
});
$(document).on('turbolinks:load', function() {
var i, table, tableElementId, tableElementIds;
tableElementIds = ['#user_table'];
i = 0;
while (i < tableElementIds.length) {
tableElementId = tableElementIds[i];
if ($.isEmptyObject($.find(tableElementId))) {
i++;
continue;
}
table = void 0;
if ($.fn.DataTable.isDataTable(tableElementId)) {
table = $(tableElementId).DataTable();
} else {
table = $(tableElementId).DataTable();
}
document.addEventListener('turbolinks:before-cache', function() {
table.destroy();
});
i++;
}
});
$(document).on('turbolinks:load', function() {
$('.select-all').click(function(e){
var checked = e.currentTarget.checked;
$('.list-item-checkbox').prop('checked', checked);
countChecked((checked) ? 20 : 0);
});
var lastChecked = null;
$('.list-item-checkbox').click(function(e){
var selectAllChecked = $('.select-all:checked').length ? true : false;
console.log(selectAllChecked)
if (selectAllChecked) {
var itemsTotal = $('.list-item-checkbox').length;
var uncheckedItemsTotal = itemsTotal - checkedItemsTotal();
var selected = 20 - uncheckedItemsTotal;
countChecked(selected);
} else {
countChecked();
}
if(!lastChecked) {
lastChecked = this;
return;
}
if(e.shiftKey) {
var from = $('.list-item-checkbox').index(this);
var to = $('.list-item-checkbox').index(lastChecked);
var start = Math.min(from, to);
var end = Math.max(from, to) + 1;
$('.list-item-checkbox').slice(start, end)
.filter(':not(:disabled)')
.prop('checked', lastChecked.checked);
countChecked();
}
lastChecked = this;
if(e.altKey){
$('.list-item-checkbox')
.filter(':not(:disabled)')
.each(function () {
var $checkbox = $(this);
$checkbox.prop('checked', !$checkbox.is(':checked'));
countChecked();
});
}
});
function countChecked(number){
number = number ? number : checkedItemsTotal();
$('#counter-selected').html(number);
}
function checkedItemsTotal(){
return $('.list-item-checkbox:checked').length;
}
$("div.toolbar").html('<b><span id="counter-selected">0</span> Selected  </b>');
});
HTML code
<div class="table-responsive" style="white-space: nowrap; overflow-x: scroll" onload="addTagfilter">
<div id="ppe_table_wrapper" class="dataTables_wrapper no-footer">
<div class="toolbar">
<b><span id="counter-selected">0</span>
Selected </b>
</div>
<div class="dt-buttons">
<button class="dt-button buttons-collection buttons-colvis btn btn-xs btn-brand dropdown-toggle" tabindex="0" aria-controls="ppe_table" type="button" aria-haspopup="true" aria-expanded="false">
<span>Column visibility</span><span class="dt-down-arrow">▼</span>
</button>
<button class="dt-button buttons-columnVisibility active" tabindex="0" aria-controls="ppe_table" type="button" data-cv-idx="0">
<span></span>
</button>
<button class="dt-button buttons-copy buttons-html5 btn btn-xs btn-brand" tabindex="0" aria-controls="ppe_table" type="button">
<span>Copy</span>
</button>
<button class="dt-button buttons-print btn btn-xs btn-brand" tabindex="0" aria-controls="ppe_table" type="button">
<span>Print</span>
</button>
<button class="dt-button buttons-csv buttons-html5 btn btn-xs btn-brand" tabindex="0" aria-controls="ppe_table" type="button">
<span>CSV</span>
</button>
<button class="dt-button buttons-excel buttons-html5 btn btn-xs btn-brand" tabindex="0" aria-controls="ppe_table" type="button">
<span>Excel</span>
</button>
</div>
<div id="ppe_table_filter" class="dataTables_filter">
<label>Filter:
<input type="search" class="" placeholder="" aria-controls="ppe_table">
</label>
</div>
<div class="dataTables_scroll">
<div class="dataTables_scrollHead" style="overflow: hidden; position: relative; border: 0px; width: 100%;">
<div class="dataTables_scrollHeadInner" style="box-sizing: content-box; width: 1437px; padding-right: 0px;">
<table class="table table-striped table-bordered table-responsive dataTable no-footer" style="width: 1437px; margin-left: 0px;" role="grid" aria-describedby="ppe_table">
<thead>
<tr role="row">
<th class="text-center sorting" tabindex="0" aria-controls="ppe_table" rowspan="1" colspan="1" style="width: 0px;" aria-label=": activate to sort column ascending" data-column-index="0"></th>
<th class="text-center sorting_asc" style="min-width: 110pt; width: 147px;" tabindex="0" aria-controls="ppe_table" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Serial: activate to sort column descending" data-column-index="1">Serial</th>
<th class="text-center sorting" style="min-width: 75pt; width: 100px;" tabindex="0" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Category: activate to sort column ascending" data-column-index="2">Category</th>
<th class="text-center sorting" style="min-width: 50pt; width: 67px;" tabindex="0" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Size: activate to sort column ascending" data-column-index="3">Size</th>
<th class="text-center sorting" style="min-width: 50pt; width: 93px;" tabindex="0" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Manufactured: activate to sort column ascending" data-column-index="4">Manufactured</th>
<th class="text-center sorting" style="min-width: 50pt; width: 109px;" tabindex="0" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Model/Style/Cut: activate to sort column ascending" data-column-index="5">Model/Style/Cut</th>
<th class="text-center sorting" style="min-width: 75pt; width: 100px;" tabindex="0" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Manufacturer: activate to sort column ascending" data-column-index="6">Manufacturer</th>
<th class="text-center sorting" style="min-width: 75pt; width: 100px;" tabindex="0" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Assigned To: activate to sort column ascending" data-column-index="7">Assigned To</th>
<th class="text-center sorting" style="min-width: 180pt; width: 240px;" tabindex="0" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Tags: activate to sort column ascending" data-column-index="8">Tags</th>
<th class="text-center sorting" style="min-width: 75pt; width: 100px;" tabindex="0" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Notes: activate to sort column ascending" data-column-index="9">Notes</th>
</tr>
</thead>
</table>
</div>
</div>
<div class="dataTables_scrollBody" style="position: relative; overflow: auto; width: 100%; max-height: 550px;">
<table id="ppe_table" class="table table-striped table-bordered table-responsive dataTable no-footer" style="width: 100%;" role="grid" aria-describedby="ppe_table_info">
<thead>
<tr role="row" style="height: 0px;">
<th class="text-center sorting" aria-controls="ppe_table" rowspan="1" colspan="1" style="width: 0px; padding-top: 0px; padding-bottom: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px;" aria-label=": activate to sort column ascending" data-column-index="0">
<div class="dataTables_sizing" style="height:0;overflow:hidden;"> </div>
</th>
<th class="text-center sorting_asc" style="min-width: 110pt; width: 147px; padding-top: 0px; padding-bottom: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px;" aria-controls="ppe_table" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Serial: activate to sort column descending" data-column-index="1">
<div class="dataTables_sizing" style="height:0;overflow:hidden;">Serial
</div>
</th>
<th class="text-center sorting" style="min-width: 75pt; width: 100px; padding-top: 0px; padding-bottom: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px;" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Category: activate to sort column ascending" data-column-index="2">
<div class="dataTables_sizing" style="height:0;overflow:hidden;">Category
</div>
</th>
<th class="text-center sorting" style="min-width: 50pt; width: 67px; padding-top: 0px; padding-bottom: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px;" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Size: activate to sort column ascending" data-column-index="3">
<div class="dataTables_sizing" style="height:0;overflow:hidden;">Size
</div>
</th>
<th class="text-center sorting" style="min-width: 50pt; width: 93px; padding-top: 0px; padding-bottom: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px;" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Manufactured: activate to sort column ascending" data-column-index="4">
<div class="dataTables_sizing" style="height:0;overflow:hidden;">
Manufactured
</div>
</th>
<th class="text-center sorting" style="min-width: 50pt; width: 109px; padding-top: 0px; padding-bottom: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px;" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Model/Style/Cut: activate to sort column ascending" data-column-index="5">
<div class="dataTables_sizing" style="height:0;overflow:hidden;">
Model/Style/Cut
</div>
</th>
<th class="text-center sorting" style="min-width: 75pt; width: 100px; padding-top: 0px; padding-bottom: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px;" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Manufacturer: activate to sort column ascending" data-column-index="6">
<div class="dataTables_sizing" style="height:0;overflow:hidden;">
Manufacturer
</div>
</th>
<th class="text-center sorting" style="min-width: 75pt; width: 100px; padding-top: 0px; padding-bottom: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px;" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Assigned To: activate to sort column ascending" data-column-index="7">
<div class="dataTables_sizing" style="height:0;overflow:hidden;">
Assigned To
</div>
</th>
<th class="text-center sorting" style="min-width: 180pt; width: 240px; padding-top: 0px; padding-bottom: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px;" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Tags: activate to sort column ascending" data-column-index="8">
<div class="dataTables_sizing" style="height:0;overflow:hidden;">
Tags
</div>
</th>
<th class="text-center sorting" style="min-width: 75pt; width: 100px; padding-top: 0px; padding-bottom: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px;" aria-controls="ppe_table" rowspan="1" colspan="1" aria-label="Notes: activate to sort column ascending" data-column-index="9">
<div class="dataTables_sizing" style="height:0;overflow:hidden;">
Notes
</div>
</th>
</tr>
</thead>
<tbody>
<tr role="row" class="odd">
<td><input type="checkbox" name="bulk_actions[ids][]" id="ppe-202" value="202" class="list-item-checkbox"></td>
<td class="sorting_1"><u><a href="/ppes/202" data-original-title="" title="">andy-test-1</a></u></td>
<td>coat
</td><td>42X36</td>
<td>2020-02-04</td>
<td></td>
<td>lion</td>
<td><u><a href="/users/19" data-original-title="" title="">Reilly,Andy</a></u></td>
<td style="text-align: left;">
</td>
<td style="text-align: left;"></td>
</tr><tr role="row" class="even">
<td class=" noVis"><input type="checkbox" name="bulk_actions[ids][]" id="ppe-145" value="145" class="list-item-checkbox"></td>
<td class="sorting_1"><u><a href="/ppes/145" data-original-title="" title="">andy-test-1124</a></u></td>
<td>trouser
</td><td>L</td>
<td>2021-01-03</td>
<td></td>
<td>lion</td>
<td><u><a href="/users/19" data-original-title="" title="">Reilly,Andy</a></u></td>
<td style="text-align: left;">
<div class="tags scaled" style="float: left"><a class="tag" id="color-tan" value="color-tan" href="http://fdstest.me.localhost:32795/manage" data-original-title="" title="">color-tan</a></div>
</td>
<td style="text-align: left;"></td>
</tr><tr role="row" class="odd">
<td class=" noVis"><input type="checkbox" name="bulk_actions[ids][]" id="ppe-253" value="253" class="list-item-checkbox"></td>
<td class="sorting_1"><u><a href="/ppes/253" data-original-title="" title="">andy-test-2</a></u></td>
<td>trouser
</td><td>36L</td>
<td>2020-03-03</td>
<td></td>
<td>lion</td>
<td><u><a href="/users/19" data-original-title="" title="">Reilly,Andy</a></u></td>
<td style="text-align: left;">
</td>
<td style="text-align: left;"></td>
</tr><tr role="row" class="even">
<td class=" noVis"><input type="checkbox" name="bulk_actions[ids][]" id="ppe-157" value="157" class="list-item-checkbox"></td>
<td class="sorting_1"><u><a href="/ppes/157" data-original-title="" title="">andy-test-3848</a></u></td>
<td>coat
</td><td>L</td>
<td>2021-01-03</td>
<td></td>
<td>lion</td>
<td><u><a href="/users/19" data-original-title="" title="">Reilly,Andy</a></u></td>
<td style="text-align: left;">
</td>
<td style="text-align: left;"></td>
</tr><tr role="row" class="odd">
<td class=" noVis"><input type="checkbox" name="bulk_actions[ids][]" id="ppe-50" value="50" class="list-item-checkbox"></td>
<td class="sorting_1"><u><a href="/ppes/50" data-original-title="" title="">andy-test-5</a></u></td>
<td>hood
</td><td>XL</td>
<td>2018-12-31</td>
<td></td>
<td>janesville</td>
<td><u><a href="/users/19" data-original-title="" title="">Reilly,Andy</a></u></td>
<td style="text-align: left;">
</td>
<td style="text-align: left;"></td>
</tr><tr role="row" class="even">
<td class=" noVis"><input type="checkbox" name="bulk_actions[ids][]" id="ppe-92" value="92" class="list-item-checkbox"></td>
<td class="sorting_1"><u><a href="/ppes/92" data-original-title="" title="">andy-test-6</a></u></td>
<td>coat
</td><td>L</td>
<td>2017-02-02</td>
<td></td>
<td>lion</td>
<td><u><a href="/users/19" data-original-title="" title="">Reilly,Andy</a></u></td>
<td style="text-align: left;">
</td>
<td style="text-align: left;"></td>
</tr><tr role="row" class="odd">
<td class=" noVis"><input type="checkbox" name="bulk_actions[ids][]" id="ppe-43" value="43" class="list-item-checkbox"></td>
<td class="sorting_1"><u><a href="/ppes/43" data-original-title="" title="">andy-test-7</a></u></td>
<td>trouser
</td><td>L</td>
<td>2018-01-01</td>
<td></td>
<td>lion</td>
<td><u><a href="/users/19" data-original-title="" title="">Reilly,Andy</a></u></td>
<td style="text-align: left;">
</td>
<td style="text-align: left;"></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="dataTables_info" id="ppe_table_info" role="status" aria-live="polite">
Showing 1 to 7 of 7 entries (filtered from 455 total entries)
</div>
</div>
</div>
This shows the initial load of the table. Note the first button in the dropdown for column visibility is:
<button class="dt-button buttons-columnVisibility active" tabindex="0" aria-controls="ppe_table" type="button" data-cv-idx="0">
<span></span>
</button>
There is nothing between the <span> tags because it is the checkbox column. If I reorder any of the columns it instantly removes it from the list of buttons. And it will stay removed since I have stateDuration: 0. But if I put the columns back into the normal order and navigate away or just hit page refresh, the empty button representing the checkbox column will reappear.
It's like the state of the column visibility is being tied to the original order of the columns... I don't even know where to troubleshoot from here.
TL:DR The table is defined with:
buttons: [
{ extend: 'colvis', position: 'dropdown', columns: ':not(.noVis)'....
And:
"columnDefs": [
{ "searchable": false, "targets": [5,6] },
{"targets": [0], "orderDataType": "dom-checkbox"},
{"targets": [0,5,6], "className": "noVis"}...
But the last line of columnDefs applying the className of noVis does not get applied when the columns are in their original order.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
