DataTables search child row content

2020-02-01 04:05发布

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

4条回答
疯言疯语
2楼-- · 2020-02-01 04:42

SOLUTION

In order for jQuery DataTables to search child rows you need to add data displayed in the child rows to the main table as hidden columns.

For example, you can add hidden column for extn data property using columns.visible option as shown below:

JavaScript:

    "columns": [
        {
            "class":          'details-control',
            "orderable":      false,
            "data":           null,
            "defaultContent": ''
        },
        { "data": "name" },
        { "data": "position" },
        { "data": "office" },
        { "data": "salary" },
        { "data": "extn", "visible": false }            
    ],

HTML:

<thead>
    <tr>
        <th></th>
        <th>Name</th>
        <th>Position</th>
        <th>Office</th>
        <th>Salary</th>
        <th>Extn.</th>
    </tr>
</thead>

DEMO

See this jsFiddle for code and demonstration. Search for 5407 and the first row will be shown even though data appears only in child row.

查看更多
做个烂人
3楼-- · 2020-02-01 04:42

if you have a list of extensions in one column then you would want to split them like this.

              {"data": "extn", "visible": false,
               "render": function (data, type, row, meta) {

                        var htmlDetail = '';                            
                        yourList.forEach(function (item) {
                            htmlDetail += item.extn + '|';
                        });
                        return type === 'display' ? htmlDetail : htmlDetail;
              }
查看更多
男人必须洒脱
4楼-- · 2020-02-01 04:43

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/

查看更多
混吃等死
5楼-- · 2020-02-01 04:44

This is quite an old thread, and the accepted answer does work, but I wanted to propose an alternate solution.

I was having the same issue not being able to search within child rows, and my solution was to make a hidden <td> on the end of my table that contained the data in the child rows - this way, the indexer sees it but the user does not.

For the limited HTML, I added a new column:

<th class="hidden">Data</th>

Then, within the DataTables call:

//Within var table = $('#table').DataTable( {....
columns : [
        //{ className : 'details-control'},
        { data : 'a' }, //a-e are the columns I want the user to see.
        { data : 'b' },
        { data : 'c' },
        { data : 'd' },
        { data : 'e' },            
        // this last one is my "index helper"
        { data : 'comments',
          render : function(data, type, full, meta) {
            return full.f + full.g + full.h + full.i;
          }
         }
    ],

Then you just need to hide this column. You could do this either through DataTables' recommended method:

https://datatables.net/examples/basic_init/hidden_columns.html

or through the method I chose:

"createdRow" : function (row,data,index) {
    $('td',row).eq(6).addClass('hidden');
}

//and the css...
.hidden {
 visibility: hidden;
}

You're left with one <td> at the end of your table that contains everything from the child rows, but it's invisible, and it works with the search box/filter thingy.

查看更多
登录 后发表回答