Jquery 数据表自定义列搜索

Jquery Datatables custom column searching

我已经对此进行了一段时间的研究,有用的信息正在枯竭而没有解决方案。

我正在使用数据tables,并且在某些列中我显示了一个已选择的多 select 框,以允许用户在添加数据后通过继续制作来编辑他们的数据select离子。

我有使用 initComplete 的每列搜索框,它们会过滤列中的数据,但不是以 acceptable 的方式;它们在选项的文本上匹配,而且在 select 元素的 类 上匹配,甚至在所有未selected 的选项上匹配,因此它是无用的。

...,
initComplete: function () {
            // Apply the search
            this.api().columns().every(function () {
                var that = this;

                $('input', this.footer()).on('keyup change clear', function () {
                    if (that.search() !== this.value) {
                        that
                            .search(this.value)
                            .draw();
                    }
                });
            });
        }

我希望它只匹配 select 框的 selected 选项的文本。 编写函数以获取给定行中 select 框的文本字符串数组对我来说很容易,但我正在努力寻找可以将此类自定义函数挂钩到 Datatable秒流.

Datatables 文档提到您可以为正交数据定义一个列过滤器函数,但没有给出这方面的示例,而且我也很难在网上找到任何示例。 我的尝试是将以下内容添加到 DataTable 初始化中,但没有被调用:

...,
"columns": [          
            {
                filter: function (a,b,c) {
                    console.log('called from column filter');
                    console.log(arguments)
                    return false;
                }
            },
            {
                filter: function (a,b,c) {
                    console.log('called to column filter');
                    console.log(arguments)                 
                    return false;
                }
            },
            null  
        ]

感谢您的宝贵时间。

更新

所以我发现我可以将一个函数推送到 $.fn.dataTable.ext.search.push(...) 上,这似乎可以满足我的需要。 沿着这条路走下去,我发现参数中传递的 html 列不包括我需要的 Chosen 生成的元素,只是预先选择的 .... 我试过使用 table.rows.invalidate.draw 但这只是从 DOM 中删除了 Chosen 元素,而不是通过让 Datatable 传入预期的 html 数据来解决这个问题。

我希望传入的实际行 html 的示例:

<td>
<select class="myclasses form-control" multiple="" style="display: none;">                    
    <option value="...">Bahamas</option>
    ...
</select>
<div class="chosen-container chosen-container-multi" title="" style="width: 437px;">
    <ul class="chosen-choices">
        <li class="search-choice">
            <span>Greece</span>
            <a class="search-choice-close" data-option-array-index="4"></a>
        </li>
        <li class="search-choice">
            <span>Belgium</span>
            <a class="search-choice-close" data-option-array-index="6"></a>
        </li>
        <li class="search-choice">
            <span>France</span>
            <a class="search-choice-close" data-option-array-index="7"></a></li><li class="search-field">
            <input class="chosen-search-input" type="text" autocomplete="off" value="Select some options" style="width: 25px;">
        </li>
    </ul>
    <div class="chosen-drop">
      <ul class="chosen-results"></ul>
    </div>
</div>
</td>

搜索调用中的实际参数数据,显示为预选状态。这就是为什么我希望 .invalidate() 解决这个问题...

<select class="myclasses form-control" multiple>                    
    <option value="...">Bahamas</option>
</select>

我现在正在考虑在将 select html 添加到 table 之前生成所选的 html。如果用户在将 select 框选项添加到 table 后对其进行更改,这可能仍然存在问题,但我会在到达那里时看到。

我认为您使用 $.fn.dataTable.ext.search 的方法是正确的方法,因为与 search() API 函数不同,这使您能够访问 DOM,您的用户 selections 可以在其中找到(即在 DataTables 对象之外)。

但是,由于 $.fn.dataTable.ext.search 不仅限于一列,还需要一些额外的工作来确保跨不同列的组合搜索仍能正常工作。

这是一个比较基础的示例,但它展示了一种方法。

每个 input 事件唯一做的就是触发 table 重绘。这种重新绘制反过来会触发全局搜索功能:

    initComplete: function () {
      var api = this.api();
      api.columns().each(function () {
        $('input', this.footer()).on('keyup change clear', function () {
          api.draw();
        });
      });
    }

搜索功能如下。代码可以精简 - 但它显示了基本方法:

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

      var fromFilter = $( '#in_0' ).val();
      var toFilter = $( '#in_1' ).val();

      var trNode = table.row( [index] ).node();

      var fromTdNode = $( "td:nth-child(1)", trNode );
      var fromSelectedValNodes = $( "select option:selected", fromTdNode );   
      var fromSelections = '';
      fromSelectedValNodes.each(function() {
        fromSelections += ( $( this ).val() + ', ' ); 
      });

      var toTdNode = $( "td:nth-child(2)", trNode );
      var toSelectedValNodes = $( "select option:selected", toTdNode );   
      var toSelections = '';
      toSelectedValNodes.each(function() {
        toSelections += ( $( this ).val() + ', ' ); 
      });
      
      if ( fromSelections.trim().toLowerCase().includes( fromFilter.trim().toLowerCase() ) &&
              toSelections.trim().toLowerCase().includes( toFilter.trim().toLowerCase() ) ) {
        return true;
      } else {
          return false;
      }
    }
  );

我们检索用户提供的两个搜索值,并将它们保存在 fromFiltertoFilter 中。

然后,对于包含多个 select 的两列中的每一列,我们检索 selected 值的文本。我们使用 DataTables API 从每个 DataTables 行中获取相关的 node() 对象。

然后我们使用 jQuery select 或将 selected 多 select 值收集到一个字符串中。

最后我们看看搜索词是否包含在我们构建的字符串中。我们分别对两列中的每一列执行此操作,以便整体 table 得到一致的过滤。

此实现假定只有 2 列包含这些选择的多 selects - 而且它们是前 2 列。

我还使用 dom 选项从 DataTable 中删除了默认的全局搜索输入框,因为这也会导致调用 $.fn.dataTable.ext.search

最后说明:我为我的小演示加载数据的方式似乎与您的数据加载不同 - 因此,如果可能需要更改,这里是我的完整独立演示:

<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Demo</title>
  <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
  <script src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.js"></script>
  <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.css">
  <link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">

  <!-- chosen select library -->
  <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.8.7/chosen.min.css">
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.8.7/chosen.jquery.min.js"></script>


</head>

<body>

<div style="margin: 20px;">

    <table id="example" class="display dataTable cell-border" style="width:100%">
        <thead>
            <tr>
                <th>From Country</th><th>To Country</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td></td><td></td>
            </tr>
            <tr>
                <td></td><td></td>
            </tr>
            <tr>
                <td></td><td></td>
            </tr>
            <tr>
                <td></td><td></td>
            </tr>
            <tr>
                <td></td><td></td>
            </tr>
        </tbody>
        <tfoot>
            <tr>
                <th></th><th></th>
            </tr>
        </tfoot>
    </table>

</div>

<script>

$(document).ready(function() {

  $('#example tfoot th').each( function ( idx ) {
    var title = $(this).text();
    $(this).html( '<input id="in_' + idx + '" type="text" placeholder="Search ' + title + '"/>' );
  } );

  var table = $('#example').DataTable( {

    dom: 'lrtip', // removed "f" for "filter".

    columnDefs: [
      {
        targets: [ 0, 1 ],
        render: function ( data, type, row ) {
          var select = $('<select multiple class="chosen-select"><option value=""></option></select>');
          select.append( '<option value="Argentina">Argentina</option>' );
          select.append( '<option value="Brazil">Brazil</option>' );
          select.append( '<option value="Cuba">Cuba</option>' );
          select.append( '<option value="Denmark">Denmark</option>' );
          select.append( '<option value="Egypt">Egypt</option>' );
          return select[0].outerHTML;
        }        
      }
    ],

    initComplete: function () {
      var api = this.api();
      api.columns().each(function () {
        $('input', this.footer()).on('keyup change clear', function () {
          api.draw();
        });
      });
    }
  } );

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

      var fromFilter = $( '#in_0' ).val();
      var toFilter = $( '#in_1' ).val();

      var trNode = table.row( [index] ).node();

      var fromTdNode = $( "td:nth-child(1)", trNode );
      var fromSelectedValNodes = $( "select option:selected", fromTdNode );   
      var fromSelections = '';
      fromSelectedValNodes.each(function() {
        fromSelections += ( $( this ).val() + ', ' ); 
      });

      var toTdNode = $( "td:nth-child(2)", trNode );
      var toSelectedValNodes = $( "select option:selected", toTdNode );   
      var toSelections = '';
      toSelectedValNodes.each(function() {
        toSelections += ( $( this ).val() + ', ' ); 
      });
      
      if ( fromSelections.trim().toLowerCase().includes( fromFilter.trim().toLowerCase() ) &&
              toSelections.trim().toLowerCase().includes( toFilter.trim().toLowerCase() ) ) {
        return true;
      } else {
          return false;
      }
    }
  );

  $(".chosen-select").chosen({
    width: "75%"
  });


} );

</script>

</body>
</html>