cooltoast cooltoast - 4 years ago 492
jQuery Question

DataTables search child row content

The DataTables search bar does not let me search for content within child rows.

I have searched extensively to find the answer to this (1, 2, 3, 4, 5, 6, 7, 8, 9), but there are little to no responses on the issue.

Here's a simple jsfiddle and DataTables debugger results.

I want to search the table for an extension number (which is in the child row), but typing one of the extension numbers into the search bar leaves no search results.

I tried the solution from this post, by adding this:

table.columns().every( function () {
var that = this;
var header = this.header();

$( 'input', this.footer() ).on( 'keyup change', function () {
that
.column( header.getAttribute('data-search-index')*1 ) // *1 to make it a number
.search( this.value )
.draw();
} );
} );


...but it still doesn't work, as you can see in the jsfiddle linked above.

Can someone please help me out?

Thanks

Answer Source

I have to ask : What make you believe you can search in child row content you are injecting dynamically only when the child rows are shown? And how should a column() search could cover content from other rows, ever?

When this said, there is of course a workaround. Instead of creating the child row content over and over, keep it in an array :

var details = [];

Now, when you are initialising the table, you initialise the child row content as well :

...
columns: [{
   className: 'details-control',
   orderable: false,
   data: null,
   defaultContent: '',
   render: function(data, type, row, meta) {  
      details[meta.row] = format(data);
   }    
}, 
...

In the format() function, add a class to the Extension Number field for easy access :

'<td class="extNo">' + d.extn + '</td>' +

When you show child rows, insert the prerendered content from details[] instead of calling format() :

if (row.child.isShown()) {
   row.child.hide();
   tr.removeClass('shown');
} else {
   row.child(details[row.index()]).show();            
   tr.addClass('shown');
}

Create a filter that returns only rows which have a details[] child row holding a certain Extension Number :

function filterByDetailsExtNo(extNo) {
    $.fn.dataTable.ext.search.push(
    function(settings, data, dataIndex) {
       return $(details[dataIndex]).find('.extNo').text() == extNo;
    }    
  )
  table.draw();
  $.fn.dataTable.ext.search.pop();
}  

Use that custom filter instead of the column() search in your input handlers :

table.columns().every( function () {
    $( 'input', this.footer() ).on( 'keyup change', function () {
        filterByDetailsExtNo(this.value);
    });
});

forked fiddle -> https://jsfiddle.net/7o67vhrz/


Update. To apply the above filter to the general searchbox :

$('.dataTables_filter input')
   .off()
   .on('keyup', function() {
      filterByDetailsExtNo(this.value);
   });    

yet another forked fiddle -> https://jsfiddle.net/ds3qp41g/


Last example. Combine details search and "native" search

function filterByDetailsExtNoAndInput(term) {
      $.fn.dataTable.ext.search.push(
        function(settings, data, dataIndex) {
            if ($(details[dataIndex]).find('.extNo').text() == term) return true;
            for (var i=0;i<data.length;i++) {
                if (data[i].toLowerCase().indexOf(term.toLowerCase())>=0) {
                    return true
                }    
            }   
            return false;
        }    
      )
      table.draw();
      $.fn.dataTable.ext.search.pop();
    }  

fiddle -> https://jsfiddle.net/h2u4fowj/

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download