Sort Arrow Icons Position

Sort Arrow Icons Position

DarrenCrDarrenCr Posts: 4Questions: 1Answers: 0
edited December 2017 in Free community support

Hi,

I have been using dataTables for a few months now and am really impressed with its capabilities.

For the dataTable I am working on currently I have activated the column sort in addition to a drop down filter for the header and a textbox filter for the footer.

Everything works but I would like to move the position of the sort arrows as they are clicked/activated every time the drop down filter is clicked - which is not ideal from a usablility point of view.

I can move the drop down filter boxes using the 'orderCellsTop: false' attribute, but the sort arrow icons also move with the drop down boxes.

I found the following solution which puts the drop down boxes in a custom css class (.filterhead) but this then creates a ghost row in the table and stops the footer filters from working.

$(".filterhead").each( function ( i ) {
    var select = $('<select><option value=""></option></select>')
        .appendTo( $(this).empty() )
        .on( 'change', function () {
               var term = $(this).val();
            table.column( i ).search(term, false, false ).draw();
        } );
         table.column( i ).data().unique().sort().each( function ( d, j ) {
            select.append( '<option value="'+d+'">'+d+'</option>' )
        } );
    } );

I have been searching for a solution for quite a while, both CSS and dataTables, but unfortunately I cannot find one.

I am using the Bootstrap4 css theme.

Here is my dataTables code -

$(document).ready(function () {         
                    
    // Setup - add a text input to each footer cell
    $('#searchResults tfoot th').each( function () {
        var title = $('#searchResults thead th').eq( $(this).index() ).text();
        //$(this).html( '<input type="text" placeholder="Search '+title+'" />' );
        $(this).html( '<input type="text" placeholder="Filter" />' );
    } );


    /* DC: this is for DataTables 1.12 */
    var table = $('#searchResults').DataTable( {
        "data": <?php if (count($this->data)){ echo $this->data; } else { echo "''"; } ?>,
        "paging":   true,
        "autoWidth": false,
        "stateSave": false,
        "order": [],
        "language": {
          "emptyTable": "No search results found"
        },
        "pagingType": "full_numbers",
        "searching": true,
        "scrollX": true,
        "scrollCollapse": true,
         // DC: use this initComplete setting if you want the select drop down filters to be put in the standard <thead><tr><th> cells
        "initComplete": function () { // DC: this adds the select menus at col header (can be changed to footer - just ensure there is a free <tr> in dataTable)
            this.api().columns().every( function () {
                var column = this;
                var select = $('<select><option value=""></option></select>')
                    .appendTo( $(column.header()).empty() )
                    .on( 'change', function () {
                        var val = $.fn.dataTable.util.escapeRegex(
                            $(this).val()
                        );

                        column
                            .search( val ? '^'+val+'$' : '', true, false )
                            .draw();
                    } );

                column.data().unique().sort().each( function ( d, j ) {
                    select.append( '<option value="'+d+'">'+d+'</option>' )
                } );
            } );
        },
        
        "orderCellsTop": false,
        "ordering": true,
    } );

    // Restore state
    var state = table.state.loaded();
    if ( state ) {
      table.columns().eq( 0 ).each( function ( colIdx ) {
        var colSearch = state.columns[colIdx].search;
        
        if ( colSearch.search ) {
          $( 'input', table.column( colIdx ).footer() ).val( colSearch.search );
        }
      } );
      
      table.draw();
    }

    // Apply the search
    table.columns().eq( 0 ).each( function ( colIdx ) {
        $( 'input', table.column( colIdx ).footer() ).on( 'keyup change', function () {
            table
                .column( colIdx )
                .search( this.value )
                .draw();
        } );
    } );
} );

Any help is appreciated.
Best Regards

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 62,296Questions: 1Answers: 10,215 Site admin
    edited December 2017

    Use orderCellsTop to shunt them up to the top cell in the multi-row header.

    Allan

    edit For clarify - you have it set to false atm. Set it to be true.

  • allanallan Posts: 62,296Questions: 1Answers: 10,215 Site admin

    Sorry - I should have read more carefully. column().header() gives you the header cell that DataTables uses itself, so using orderCellsTop set to true would put the sort icon into the top row, but it would also move the input box since you are using column().header() as you are seeing.

    The answer is that you do need to use orderCellsTop, but you also need to change how you are getting the cell to insert the input element into from:

    appendTo( $(column.header()).empty() )

    To:

    appendTo( $('#searchResults thead tr:eq(1) th').eq(i).empty() )
    

    Allan

  • DarrenCrDarrenCr Posts: 4Questions: 1Answers: 0

    Thanks for that Allan, it has shown me where the problem lies.

    Unfortunately I still cannot get it to function correctly, although it is getting better as the sort arrows function as does the footer text filters.

    The drop downs are populated with the correct data, and apply the correct filter when selected, but they disappear once selected.

    The drop down select filters appear to be placed in the first row of the dataTable, even though the appendTo specifies that it is to go into the <thead>. Which may be why they are do not appear when the table is redrawn?

    I added a counter for the i variable used in your .appendTo solution to traverse all the columns

    <thead>
        <tr>
            <th>SONo:Ln:Rq</th>
            <th>PO</th>
            <th>Group</th>
            <th>Account</th>
            <th>Currency</th>
            <th>Customer Name</th>
            <th>Cust PN</th>
            <th>Cat PN</th>
            <th>Spec PN</th>
            <th>Request Date</th>
            <th>Promise Date</th>
            <th>Open Quantity</th>
            <th>EDI Flag</th>
        </tr>
                        
        <tr>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
        </tr>
    </thead>
    
    var table = $('#searchResults').DataTable( {
        "data": <?php if (count($this->data)){ echo $this->data; } else { echo "''"; } ?>,
        "paging":   true,
        "autoWidth": false,
        "stateSave": false,
        "order": [],
        "language": {
          "emptyTable": "No search results found"
        },
        "pagingType": "full_numbers",
        "searching": true,
        "scrollX": true,
        "scrollCollapse": true,
        "initComplete": function () {
            var i = 0;
            this.api().columns().every( function () {
                var column = this;
                var select = $('<select><option value=""></option></select>')
                    .appendTo( $('#searchResults thead tr:eq(1) th').eq(i).empty() )
                    .on( 'change', function () {
                        var val = $.fn.dataTable.util.escapeRegex(
                            $(this).val()
                        );
    
                        column
                            .search( val ? '^'+val+'$' : '', true, false )
                            .draw();
                    } );
    
                column.data().unique().sort().each( function ( d, j ) {
                    select.append( '<option value="'+d+'">'+d+'</option>' )
                } );
                i++;
            } );
        },
        "orderCellsTop": true,
        "ordering": true,
    } );
    

    I've added screenshots of the 3 stages to help explain.

    Many thanks for your help.

  • allanallan Posts: 62,296Questions: 1Answers: 10,215 Site admin
    Answer ✓

    Could you link to a page showing the issue please? The first two parts of the screenshot appear to show it working as I would have expected. The third part appears to show it with the filter elements removed. I don't know why that would be happening.

    Allan

  • DarrenCrDarrenCr Posts: 4Questions: 1Answers: 0

    Hi Allan, unfortunately this is hosted on an intranet testing server so I cannot provide a link.

    I'll give it another few hours of work, but ultimately may have to remove the sort arrows, to allow the dynamic drop down filter menus to work.

    If I do find a solution, I'll post it here.

    Thanks for your help.

  • DarrenCrDarrenCr Posts: 4Questions: 1Answers: 0

    I've found the solution.

    DataTables seems to create separate tables for the <thead> <tbody> and <tfoot>, so 3 tables in all. Only 1 of which uses the #id (in my case #searchResults), which is the <tbody> table.

    I removed the #searchResults from the .appendTo and this now puts the dynamic drop down filters in the correct position (the <thead> table).

    Here is the code for the dataTables

    var table = $('#searchResults').DataTable( {
        "data": <?php if (count($this->data)){ echo $this->data; } else { echo "''"; } ?>,
        "paging":   true,
        "autoWidth": false,
        "stateSave": false,
        "order": [],
        "language": {
          "emptyTable": "No search results found"
        },
        "pagingType": "full_numbers",
        "searching": true,
        "scrollX": true,
        "scrollCollapse": true,
        "initComplete": function () {
            var i = 0;
            this.api().columns().every( function () {
                var column = this;
                var select = $('<select><option value=""></option></select>')
                    .appendTo( $('thead tr:eq(1) th').eq(i).empty() )
                    .on( 'change', function () {
                        var val = $.fn.dataTable.util.escapeRegex(
                            $(this).val()
                        );
    
                        column
                            .search( val ? '^'+val+'$' : '', true, false )
                            .draw();
                    } );
    
                column.data().unique().sort().each( function ( d, j ) {
                    select.append( '<option value="'+d+'">'+d+'</option>' )
                } );
                i++;
            } );
        },
        
        "orderCellsTop": true,
        "ordering": true,
    } );
    

    I have also attached a screenshot of the final result.

    Many thanks for your help Allan.

    Happy New Year.

  • allanallan Posts: 62,296Questions: 1Answers: 10,215 Site admin

    Nice one - great to hear you've got it working and thanks for posting back.

    Happy New Year!
    Allan

This discussion has been closed.