DataTables search child row content
Asked Answered
T

4

16

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

Tremaine answered 27/5, 2015 at 0:12 Comment(0)
B
18

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.

Beryl answered 23/10, 2015 at 2:36 Comment(2)
this is a far better solution from what i've seen out there and does not require any additional code. clean and simple. thanks for sharing!Adamandeve
this is really useful, but how can I do to show the child row as well as the parent, when the searched data appears only in the child? If the searched data appears only in the parent, the child should remain hidden, and only the parent displayed.Reprehend
S
3

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/

Sergias answered 27/5, 2015 at 7:45 Comment(6)
thanks for the response! I may not have worded my question properly: is there any way I can add this custom filter function to the DataTables global search bar on the top right? Do I just have to set the $.fn.dataTable.ext.search.push() method like in this link?Tremaine
Hey @cooltoast, the filters works globally, all the time - thats why I pop() it at the end. I am not completely sure what you ask, do you want the search input to be attached to a filter function as above in general?Sergias
in your jsfiddle, if you search "1562" in the top right search bar, nothing shows up (but it does work for the individual column search bars on the bottom). Since my actual app doesn't have those column search bars, I would like to attach the custom filter function to the search bar at the top right. Can that be done with the DataTables API?Tremaine
hmm it seems now that I cannot search for names or any content besides extension numbers (try searching for "Tiger"). Is it possible to retain the original search bar functionality and add the filter function to search for extension numbers as well? (Once again, sorry for not explaining my question properly)Tremaine
@cooltoast, you are hard to satisfy :) It should be a nobrainer, but have made an example and a fiddle anyway. Last edit from me.Sergias
It works! Thanks again @davidkonrad, you the real mvpTremaine
B
2

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.

Brominate answered 31/8, 2015 at 15:32 Comment(4)
I am thinking I will end up having to do this but I would like to avoid this as it will create bloated ajax calls for my table. Problem with my child rows (row rather) is that the row is a html table and the fields in that table are what I want to search so including the table within the main column is just going to be annoying. I will see what I can do though might be able to improve on this.Aurlie
This is my scenario as well - I have a child row that's just comprised of a massive html table, populated with the other json records I didn't want in the "header" row (that the user clicks on). I found that the time it takes to return the extra hidden row is not a hindrance to me - if it is for you, maybe the accepted answer is the solution?Brominate
Possibly I had almost finished work at that point yesterday so didn't take it any further, Having thought on it I will convert my child row field from a table to a object within the json itself and loop through that object to generate a child table on the fly. I will let you know how I get on, I will be dealing with 1000+ rows when im finished so anything I can do to minimize the ajax data will help.Aurlie
@BrianPowell Do you have a working example, in jfidde or somewhere. Trying to create a dynamic table with searchable child rows. I dont know js, but I can copy and paste it.Oblation
P
0

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;
              }
Professional answered 18/12, 2019 at 12:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.