jQuery DataTables基于多个值过滤行

3
我正在尝试使用多个过滤器根据选择的过滤器隐藏/显示我的数据表中的行。我的计划是将过滤器值放入一个数组中,并将它们与第一列中的data-search属性进行比较,但我目前的代码不起作用。
这里有一个带有复选框过滤器和表格数据的JSfiddle,下面是代码: https://jsfiddle.net/dmcgrew/06j4pxjk/3/
<label>
    <input type="checkbox" name="cat" value="cat" class="filter"> Cats
</label>

<label>
    <input type="checkbox" name="dog" value="dog" class="filter"> Dogs
</label>

<table class="select_items">
    <thead>
        <tr>
            <th>Item</th>
            <th>Description</th>
            <th>Crest Allowed</th>
            <th>&nbsp;</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-search="cat">1</td>
            <td>Testing Bowl</td>
            <td>NO</td>
            <td><button class="button">Select</button></td>
        </tr>
        <tr>
            <td data-search="dog">32</td>
            <td>Cup Test</td>
            <td>NO</td>
            <td><button class="button">Select</button></td>
        </tr>
        <tr>
            <td data-search="dog">3335</td>
            <td>Bowl Test</td>
            <td>NO</td>
            <td><button class="button">Select</button></td>
        </tr>

    </tbody>
</table>

The JS..

var select_items = $('.select_items').DataTable();

var filters = [];

$('input.filter').on('change', function(){
   var filters = [];
   $("input.filter:checked").each(function(){

    var checkedBox = $(this).val();
    if (filters.indexOf(checkedBox) === -1){
        filters.push(checkedBox);
    }
   });

   console.log(filters);

   if(this.checked){
      $.fn.dataTable.ext.search.push(
         function (settings, data, dataIndex){
            return (data[0].indexOf(filters) > -1) ? true : false;
         }
      );
   } 

   select_items.draw();

   if(this.checked){
      $.fn.dataTable.ext.search.pop();    
   }
});

这对我有效 https://jsfiddle.net/06j4pxjk/2/ - Hackerman
不完全正确。当我两个都选择的时候,我没有看到任何结果。我应该能够看到所有3行。而且,如果我选择了两者,然后取消选择“Dogs”,我仍然可以看到所有3行,但实际上我只应该能够看到第一行。 - Dustin
你想让过滤器像“或”而不是“与”一样起作用吗? - Hackerman
是的,如果有人选择了猫和狗,它将显示包含猫或狗的行。 - Dustin
3个回答

3

考虑到已接受的答案涉及遗留接口fnFilter,并且截至DataTables 1.10版本,建议使用新API,因此我将提供更为时新的解决方案,这是我认为更加可扩展、整洁和简单的方法:

//define statical data
var srcData = [
  {search: 'Cat', item: '1', descr: 'Testing Bowl', crest: 'NO'},
  {search: 'Dog', item: '32', descr: 'Cup Test', crest: 'NO'},
  {search: 'Dog', item: '3335', descr: 'Bowl Test', crest: 'NO'},
];
//define dataTable object
var dataTable = $('#mytable').DataTable({
  sDom: 't',
  data: srcData,
  columns: [
    {title: 'Item', data: 'item'},
    {title: 'Description', data: 'descr'},
    {title: 'Crest Allowed', data: 'crest'},
  ]
});
//put in place dynamically created checkboxes
var searchValues = [];
dataTable.data().sort().toArray().forEach(row => {
  if(searchValues.indexOf(row.search)==-1) searchValues.push(row.search);
});
var checkboxes = searchValues.reduce((html, item) => html += `<input type="checkbox" value="${item}" class="filter">${item}</input>`,'');
$(checkboxes).insertBefore($('#mytable'));
//employ $.fn.DataTable.ext.search
var lookupValues = [];
$.fn.DataTable.ext.search.push((settings, row, index, rowObj) => lookupValues.indexOf(rowObj.search) > -1 || lookupValues.length == 0);
//watch checkboxes and redraw table on change accordingly
$(".filter").on('change', () => {
  lookupValues = [...$('.filter:checked')].map(checkbox => $(checkbox).val());
  dataTable.draw();
});
<!doctype html>
<html>
<head>
  <script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
  <script type="application/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
  <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
</head>
<body>
  <table id="mytable"></table>
</body>
</html>


2
我在你的代码中做了一些修改,使用了fnFilter API:

文档:https://datatables.net/docs/DataTables/1.9.0/DataTable.html#fnFilter

$(function() {
  otable = $('.select_items').dataTable();
})

function filterme() {
  //build a regex filter string with an or(|) condition
  var types = $('input:checkbox[name="filter"]:checked').map(function() {
    return '^' + this.value + '\$';
  }).get().join('|');
  //filter in column 0, with an regex, no smart filtering, no inputbox,not case sensitive
  otable.fnFilter(types, 0, true, false, false, false);  
}

您可以在这里看到它的运行效果:JSFiddle演示

这很棒..但是有什么想法为什么在dom准备好后包装它时它不起作用? - Dustin
没事了,我看到了dataTable()和DataTable()之间的区别。我需要阅读一些相关内容。谢谢你的帮助! - Dustin
你知道有没有办法让它在多列中工作吗?我还有一些列2的数据也想要过滤。 - Dustin
你可以创建另一个更详细的问题,并将链接作为评论添加在这里...我会看一下 :) - Hackerman
没问题,这是链接:https://stackoverflow.com/questions/48229250/datatables-how-to-filter-across-multiple-columns - Dustin

1

你需要检查 filter 的长度。

如果没有 filter$.fn.dataTable.ext.search.push 函数必须对所有行返回 true

而且,我认为 search.pop() 也应该适用于取消选择...

var select_items = $('.select_items').DataTable();


$('input.filter').on('change', function(){
  var filters = [];
  $("input.filter:checked").each(function(){
    var checkedBox = $(this).val();
    if (filters.indexOf(checkedBox) === -1){
      filters.push(checkedBox);
    }
  });

  console.log(filters.length);

  $.fn.dataTable.ext.search.push(function(settings, data, dataIndex){
    if(filters.length>0){
      return (data[0].indexOf(filters) > -1) ? true : false;
    }else{
      return true;
    }
  });

  select_items.draw();
  $.fn.dataTable.ext.search.pop();
});

更新的 Fiddle


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接