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

js_natimarkjs_natimark Posts: 3Questions: 1Answers: 0
edited January 2023 in Free community support

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

  • kthorngrenkthorngren Posts: 21,299Questions: 26Answers: 4,945

    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

  • js_natimarkjs_natimark Posts: 3Questions: 1Answers: 0
    edited January 2023

    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.

  • kthorngrenkthorngren Posts: 21,299Questions: 26Answers: 4,945
    Answer ✓

    Thanks for the test case, it helps! There are a couple issues. Your selector $('.filters th') is not specific enough to find the correct th elements. When using the Datatables scrolling options, ie scrollX, scrollY, Datatalbes. clones the original header to facilitate scrolling. Let me explain with these steps.

    1. Open your test case.
    2. Click Console (beta) to open the jsfiddle console.
    3. Enter $('.filters th').length in the console, you will see 0 since no tabs have been opened.
    4. Open the first tab then enter the same $('.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.
    5. Open tab 2 and enter $('.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.
    6. Go to tab 1, type 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.
    7. In the console type $('.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:

    <div id="tab_1Table_wrapper" class="dataTables_wrapper no-footer"><div class="dataTables_scroll"><div class="dataTables_scrollHead" style="overflow: hidden; position: relative; border: 0px; width: 100%;">
    

    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

  • js_natimarkjs_natimark Posts: 3Questions: 1Answers: 0

    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.

Sign In or Register to comment.