Is it possible to filter a jQuery DataTable by data attribute?
Asked Answered
S

4

7

I was wondering if it is at all possible to filter a jQuery DataTable by one of its data attributes instead of the contents of its cells. To dynamically apply a filter to a column, one uses this call:

$table.fnFilter('^(Some value)$', columnIndex, true, false);

This will filter the exact contents of the cell by default using regex. However, assume that my cells are structured this way:

<td data-label="Active"><i class="fa fa-check fa-lg"></i></td>

Or

<td data-label="Active">Active<br /><span class="mute">Some text</span></td>

I would like to be able to have the DataTable filter by the exact content of the attribute data-label instead of the cell contents. Is it a matter of defining the search type when setting up columns on table init? Or is there a way to define to filter by attribute instead of contents?

Superinduce answered 16/7, 2015 at 15:9 Comment(3)
How are you generating table ... json or existing html? Simple suggestion would be use extra column that isn't visibleBehold
@charlietfl, currently html, but I would like to apply it to json as well. Would it really matter though? Ah yes, putting that extra hidden column, I've had that workaround. Let's say I cannot use that option.Superinduce
Well in json model you already would have data to use as filter value and the attribute would be redundantBehold
F
14

If you want to trigger the filter by code, create a custom filter :

$.fn.dataTable.ext.search.push(
   function(settings, data, dataIndex) {
      var dataLabel = table
          .row(dataIndex)         //get the row to evaluate
          .nodes()                //extract the HTML - node() does not support to$     
          .to$()                  //get as jQuery object 
          .find('td[data-label]') //find column with data-label
          .data('label');         //get the value of data-label
      return dataLabel  == 'Active'; 
   }     
);

demo -> http://jsfiddle.net/x83zm7qq/

If you just want to be able to use data-label as the target of filtering when the user types in the searchbox, you can rename data-label to data-search or data-filter :

<td data-search="Active"><i class="fa fa-check fa-lg"></i></td>

dataTables calls it orthogonal data.

Farlee answered 18/7, 2015 at 3:28 Comment(12)
Yes that did it. Having either a data-search or data-filter attribute in the td element allowed me to filter the cells by their values. Thanks!Superinduce
how to do this on legacy version?Friendship
@Farlee This does not work with version 1.10. Any ideas how to get the 'data-sort' value within this function?Bilek
@alwaysVBNET, could you show an example of the row or column markup? What version are you using? This is meant to work with 1.10.x ...Farlee
@Farlee I asked the question here and answered it myself. Do you think my own answer is efficient or is there a better way to get the data: #49467625Bilek
Hey @alwaysVBNET, it looks OK. +1. I believe it is more efficient since you operate on the ready-to-use settings object, not walking through methods.Farlee
@Farlee niceBilek
@mmcrae, "so there's really no way to just say $(myDataTable).filter(function(row) { comparison logic }.... on the fly to filter it? It has to go thru this global ext.search.push" Yes, there is no "native" workaround, it need some programming.Farlee
@Farlee - and dtTable.draw() is what triggers all searches that have been pushed, correct? And then re. my other comment and then how would you pass parameters into the search?... looks like I'll need to do a jQuery query to find whatever params I want since params cannot directly be passed to the funcDistort
@mmcrae See #55243322, since you posted your comment i realized there may be a solution (not the first time this is issued) I have posted a question and answer it myself in a little while.Farlee
This might work only if you have one datatable. In a case of multiple datatables, this doesn't workOssiferous
@Reddy, but why downvote the right answer? DataTables does not support filtering on different tables, you only have one filter in total, and must code your way out if you use multiple tables. RTFM!Farlee
X
3

you may also define a per-table custom callback by storing it in "settings" in initComplete callback and then invoking in from instance's "settings" object under common search handler. Here's the code:

$(function(){
  // the common/unified plugin (for all datatables)
  $.fn.DataTable.ext.search.push(
        function(settings, columnsOutput, dataIndex, data, outputIndex) {
          // this = ext.search array (all custom search functions (including this one)
          if (settings._myFilter){
              return settings._myFilter.call(settings, {
                  data: data,
                  dataIndex: dataIndex,
                  outputIndex: outputIndex,
                  columnsOutput: columnsOutput,
                  settings: settings
              });
          } else {
              return true;
          }
      }
      );

  // exact datatable initialization
  var dTable = $("#example").DataTable({
    // some sample data
    data: [{name: "John"}, {name: "Jack"}, {name: "Andy"}],
    columns: [{data: 'name'}],
    // setting our custom function under the initComplete callback
    initComplete: function(settings, json) {
      settings._myFilter = function(info){
        if ($('#jFilter').prop('checked')){
          return (info.data.name.toLowerCase().indexOf('j') >= 0);
        } else {
          return true;
        }
      }
    }
  });
  
  $('#jFilter').on('click', function(){
    dTable.draw(); // redraw will apply all the filters
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdn.datatables.net/1.10.0/js/jquery.dataTables.js"></script>
<link href="https://cdn.datatables.net/1.10.0/css/jquery.dataTables.css" rel="stylesheet"/>

<h2>Click checkbox below to filter by data using a callback</h2>
<label><input id="jFilter" type="checkbox"> J only</label>

<table id="example">
</table>
Xerox answered 6/4, 2018 at 20:3 Comment(0)
D
1
var detailDT = $("#staging-detail-table").DataTable();

var selectedHeaderId = $(...).click...

$.fn.dataTable.ext.search.push(
       function (settings, searchData, dataIndex, rowData) {

            // This is a global call-back, so check what table is getting sent thru
            // for different search logic.
            // This is triggered any time any table is re-drawn.

            // Detail grid
            if (settings.nTable.id == "staging-detail-table") {
                if (!selectedHeaderId) {
                    // no header was selected. show everything
                    return true;
                } else {
                    var $trDetailDT = $(detailDT.row(dataIndex).node());
                    var headerId = $trDetailDT.data("headerid");

                    return selectedHeaderId == headerId;
                }
            }

            return true; // it wasnot the staging data table. Don't filter/limit.
        }
)

detailDT is a reference to the DataTable I want to filter.

selectedHeaderId is the value I want to filter by - would have been set by some other jQuery user interaction etc. before calling detailDT.draw() which triggers the search.

Key part is calling $(detailDT.row(dataIndex).node()); which uses the callback param dataIndex of the current row. This basically gets the row into a normal jQuery object to get data attributes etc.

Distort answered 20/3, 2019 at 14:15 Comment(0)
N
1

I am a little late here but I see another solution that simplify this issue: In HTML: Pick a column to filter your data: (I pick 1st column)

<td><div data-filter="filter1" >...</div></td>

In JS:

 $.fn.dataTable.ext.search.push( (settings, data, dataIndex, rowData ) =>{ 
            var row=$(rowData[0]); 
            var filterData = $(rowData[0]).attr('data-filter');
            return filter === 'filter1';
           });
Nickinickie answered 20/10, 2021 at 17:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.