Many tables in tabs on a single page not initializing column search boxes correctly
Many tables in tabs on a single page not initializing column search boxes correctly
Description of problem:
So, I'm updating some older code using unsupported table objects to DataTables.net
I've done multiple tables on another page, but they didn't need searching, only sorting, and I've liked the utility of DataTables.net so far.
On this page, though, once I got past the first couple tabs with tables, if I click on more than one tab on the page the DataTables simply has 2 duplicate header rows, instead of generating the column search inputs, as per this example Column Filtering. The data itself loads just fine, it's just the init of the inputs for column searching that's not working, and I'm having trouble finding anything relevant for this scenario, as each table needs its own unique data and initialization.
Screen grab of the problem: Almost all of the visible columns have searchable columns on their table. Notes tab was the second tab selected after page load. If it's the first then it loads just fine, whatever tab you select first loads fine.
Here's the initialization function I'm using for one of the tables... other than html ID and different calls/columns for server side processing all of the tables initialize the same.
// Init function copied from .js file
function initTable() {
$('#dataTable thead tr')
.clone(true)
.addClass('filters')
.appendTo('#dataTable thead');
var table = $('#dataTable').DataTable({
scrollY: "400px",
scrollX: "900px",
pageLength: 50,
orderCellsTop: true,
dom: "tr" +
"<'my-wrapper'<'pagination'p><'dt-info'i>>",
searching: true,
processing: true,
search: {
return: true
},
serverSide: true,
ajax: {
url: noteUrl + "?cid="+$('#Company_Id').val(),
type: "POST",
},
autoWidth: false,
order: [[0, 'desc']],
columns: [
{
data: "CreateDate", width: "10%",
render: function (data, type) {
if (data != "") {
let date = formatDateTime(data)
return type === 'display'
? date : data;
} else { return data; }
},
},
{ data: "NoteType", width: "10%" },
{ data: "User", width: "10%" },
{ data: "NoteContent" }
],
initComplete: function () {
var api = this.api();
// For each column
api
.columns()
.eq(0)
.each(function (colIdx) {
// Set the header cell to contain the input element
var cell = $('.filters th').eq(
$(api.column(colIdx).header()).index()
);
var title = $(cell).text();
if (this.settings()[0].aoColumns[colIdx].bSearchable) {
$(cell).html('<input type="text" placeholder="' + title + '" />');
} else { $(cell).html(''); }
// On every keypress in this input
$(
'input',
$('.filters th').eq($(api.column(colIdx).header()).index())
)
.off('change')
.on('change', function (e) {
// Get the search value
$(this).attr('title', $(this).val());
var regexr = '({search})'; //$(this).parents('th').find('select').val();
var cursorPosition = this.selectionStart;
// Search the column for that value
api
.column(colIdx)
.search(
this.value != ''
? this.value
: '',
false,
false
)
.draw();
})
//.on('keyup', function (e) {
// e.stopPropagation();
// $(this).trigger('change');
// $(this)
// .focus()[0]
// .setSelectionRange(cursorPosition, cursorPosition);
//})
;
//api.columns.adjust();
});
},
});
}
This question has an accepted answers - jump to answer
Answers
Its hard to debug without seeing the problem. Please provide a link to your page or a test case replicating the issue so we can help debug.
https://datatables.net/manual/tech-notes/10#How-to-provide-a-test-case
Kevin
Here's a JSfiddle example with similar structure to what I'm having trouble with. The primary difference is that I have a seperate file for each init function and I'm using server side processing. however when I tested in jsfiddle it behaves the same without server side.
Just click a couple tabs and you'll see that after the first tab the filter inputs for each column don't load.
I'm not sure if I've got a JS issue, or a DataTables.net issue. I'm still learning JS.
Thanks for the test case, it helps! There are a couple issues. Your selector
$('.filters th')
is not specific enough to find the correctth
elements. When using the Datatables scrolling options, iescrollX
,scrollY
, Datatalbes. clones the original header to facilitate scrolling. Let me explain with these steps.Console (beta)
to open the jsfiddle console.$('.filters th').length
in the console, you will see0
since no tabs have been opened.$('.filters th').length
you will see 14. This is due to the cloned header. 7 for the original header and 7 for the cloned header.$('.filters th').length
. You will see 24. 14 (7 + 7) for tab1 and 10 (5 _ 5) for tab 2. When open the second tab the selector finds the filters for the first tab and applies the search.2
and. hit enter in the Date column search. The search isn't applied. Go to tab 2 and you will see the search is applied to tab 2.$('.filters th', '#tab_1Table_wrapper').length
. You will see 14 not 24. Type$('.filters th', '#tab_2Table_wrapper').length
for tab 2 and you will see 10.When Datatables clones the header it places the header in a
div
with the id of the table id with_wrapper
appended, for example:You can see this by right clicking the header and using Inspect.
I added the more specific selector to tab 1 and tab 2 so you can see it work:
https://jsfiddle.net/z968ye1c/9/
Kevin
This change got my tables working on the page!
Thank you so much for helping with this!
Selectors can be so confusing if you're not used to thinking like that... LOL... I also have issues defining them for CSS.
I was all focused on the .eq(0) line, thinking it was resolving the wrong table in the api...
It's hard to bounce from C# to JS, sometimes... especially with something like this. I was so focused on the code and didn't even think that the selector the code was running against might be the problem.
I'll see you next time I run into an issue I can't wrap my head around.