如何在数据表中使用输入字段添加最小和最大范围过滤器?

Posted

技术标签:

【中文标题】如何在数据表中使用输入字段添加最小和最大范围过滤器?【英文标题】:How to add minimum and maximum range filter with input field in datatable? 【发布时间】:2021-10-07 17:04:45 【问题描述】:

我有一个包含多列的表,每列都有一个输入字段来搜索特定列。

但是对于基于数字的 4 列,我想要一个范围过滤器。这意味着,这 4 列将有两个输入字段,第一个是输入最小范围号,第二个是输入最大范围号。看一下参考图片(它只有 2 列在 4 个基于数字的列中,另外 2 个在屏幕截图中不可见)。

现在我正在尝试通过将我自己的搜索函数添加到数据表搜索函数数组来实现此功能,如文档中所述。 https://datatables.net/examples/plug-ins/range_filtering.html

但是搜索不起作用,或者我说它根本没有对 UI 进行任何更改。

这是代码 -

// Call the dataTables jQuery plugin
$(document).ready(function() 

  // Setup - add a text input to each footer cell
  $('#dataTable thead tr').clone(true).appendTo('#dataTable thead');
  $('#dataTable thead tr:eq(1) th').each( function (i) 
    var title = $(this).text();
    if(title==='clicks' || title==='impressions' || title==='ctr' || title==='position') 
      $(this).html(`
        <div class='d-flex'>
          <input name=$title_min id=$title_min class='' type='number' min='0' placeholder='Min' style='width: 80px;'/>
          <input name=$title_max id=$title_max class='ml-1' type='number' min='0' placeholder='Max' style='width: 80px;'/>
        </div>
      `);

      var minInputValue = parseFloat($(`input[id=$title_min]`, this).val()) || 0;
      var maxInputValue = parseFloat($(`input[id=$title_max]`, this).val()) || 0;

      $.fn.dataTable.ext.search.push(function (settings, data, dataIndex) 
        // logic to filter min and max values
        var colVal = parseFloat(data[i]) ||  0;
        if (colVal >= minInputValue || colVal <= maxInputValue || minInputValue === 0 || maxInputValue === 0) 
          return true;
        
        return false;
      );

      $(`#$title_min`, this).on('keyup change', function () 
        minInputValue = parseFloat($(this).val()) || 0;
        console.log('min', minInputValue);
        dataTable.draw();
      );

      $(`#$title_max`, this).on('keyup change', function () 
        maxInputValue = parseFloat($(this).val()) || 0;
        console.log('max', maxInputValue);
        dataTable.draw();
      );

     else 
      $(this).html('<input type="text" placeholder="Search '+title+'" />');
      $('input', this).on('keyup change', function () 
        if (dataTable.column(i).search() !== this.value) 
          dataTable.column(i).search(this.value).draw();
        
      );
    
  );

  var dataTable = $('#dataTable').DataTable(
    orderCellsTop: true,
    paging: true,
    scrollX: 400,
    searching: true,
    // lengthMenu: true,
    dom: 'Blfrtip',
    buttons: [
       extend: 'csv', className: 'mb-2 btn btn-sm btn-info', 
       extend: 'excel', className: 'mb-2 btn btn-sm btn-info' ,
       extend: 'pdf', className: 'mb-2 btn btn-sm btn-info' ,
       extend: 'print', className: 'mb-2 btn btn-sm btn-info' ,
    ]
  );

  $('#dataTable_wrapper .dataTables_length').css( display: 'inline-flex', 'margin-left': '20px' )
);

非常感谢您的帮助。

【问题讨论】:

【参考方案1】:

您的方法很接近,但是您需要在过滤器函数中扩展逻辑:

$.fn.dataTable.ext.search.push(function (settings, data, dataIndex) 
  
  // gather all the inputs we will need:
  var clicks_val = parseFloat(data[2]) ||  0.0;
  var clicks_min = parseFloat($('#clicks_min').val()) || 0;
  var clicks_max = parseFloat($('#clicks_max').val()) || Number.MAX_VALUE;
  var impressions_val = parseFloat(data[3]) ||  0.0;
  var impressions_min = parseFloat($('#impressions_min').val()) || 0;
  var impressions_max = parseFloat($('#impressions_max').val()) || Number.MAX_VALUE;

  // evaluate to true to filter in a row, or false to filter it out:
  var clicks = (clicks_val >= clicks_min && clicks_val <= clicks_max);
  var impressions = (impressions_val >= impressions_min && impressions_val <= impressions_max);

  // combine the above evaluations for overall row filtering:
  return clicks && impressions;
);

在这里,我明确收集了决定一行是否应该可见或过滤掉所需的所有输入。

一个演示:

$(document).ready(function() 

  $.fn.dataTable.ext.search.push(function (settings, data, dataIndex) 
    // gather all the inputs we will need:
    var clicks_val = parseFloat(data[2]) ||  0.0;
    var clicks_min = parseFloat($('#clicks_min').val()) || 0;
    var clicks_max = parseFloat($('#clicks_max').val()) || Number.MAX_VALUE;
    var impressions_val = parseFloat(data[3]) ||  0.0;
    var impressions_min = parseFloat($('#impressions_min').val()) || 0;
    var impressions_max = parseFloat($('#impressions_max').val()) || Number.MAX_VALUE;

    // evaluate to true to filter in a row, or false to filter it out:
    var clicks = (clicks_val >= clicks_min && clicks_val <= clicks_max);
    var impressions = (impressions_val >= impressions_min && impressions_val <= impressions_max);

    // combine the above evaluations for overall row filtering:
    return clicks && impressions;
  );

  // Setup - add a text input to each footer cell
  $('#dataTable thead tr').clone(true).appendTo('#dataTable thead');
  $('#dataTable thead tr:eq(1) th').each( function (i) 
    var title = $(this).text();
    if(title==='clicks' || title==='impressions' ) 
      $(this).html(`
        <div class='d-flex'>
          <input name=$title_min id=$title_min class='' type='number' min='0' placeholder='Min' style='width: 80px;'/>
          <input name=$title_max id=$title_max class='ml-1' type='number' min='0' placeholder='Max' style='width: 80px;'/>
        </div>
      `);

      $(`#$title_min`, this).on('keyup change', function () 
        minInputValue = parseFloat($(this).val()) || 0;
        dataTable.draw();
      );

      $(`#$title_max`, this).on('keyup change', function () 
        maxInputValue = parseFloat($(this).val()) || 0;
        dataTable.draw();
      );

     else 
      $(this).html('<input type="text" placeholder="Search '+title+'" />');
      $('input', this).on('keyup change', function () 
        if (dataTable.column(i).search() !== this.value) 
          dataTable.column(i).search(this.value).draw();
        
      );
    
  );

  var dataTable = $('#dataTable').DataTable(
    orderCellsTop: true,
    paging: true,
    scrollX: 400,
    searching: true,
    // lengthMenu: true,
    dom: 'Blfrtip',
    buttons: [
       extend: 'csv', className: 'mb-2 btn btn-sm btn-info', 
       extend: 'excel', className: 'mb-2 btn btn-sm btn-info' ,
       extend: 'pdf', className: 'mb-2 btn btn-sm btn-info' ,
       extend: 'print', className: 'mb-2 btn btn-sm btn-info' ,
    ]
  );

  $('#dataTable_wrapper .dataTables_length').css( display: 'inline-flex', 'margin-left': '20px' )
);
<!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">

</head>

<body>

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

    <table id="dataTable" class="display dataTable cell-border" style="width:100%">
        <thead>
            <tr>
                <th>page</th>
                <th>query</th>
                <th>clicks</th>
                <th>impressions</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>https://google.comn</td>
                <td>foo bar</td>
                <td>1.2</td>
                <td>3.4</td>
            </tr>
            <tr>
                <td>https://google.comn</td>
                <td>foo bar</td>
                <td>2.3</td>
                <td>4.5</td>
            </tr>
            <tr>
                <td>https://google.comn</td>
                <td>foo bar</td>
                <td>3.4</td>
                <td>5.6</td>
            </tr>
        </tbody>
    </table>

</div>

</body>
</html>

另请注意,我们不再需要这些:

var minInputValue = parseFloat($(`input[id=$title_min]`, this).val()) || 0;
var maxInputValue = parseFloat($(`input[id=$title_max]`, this).val()) || 0;

更新

这是使您的代码更“通用”的一种方法 - 我的意思是您不必为每个单元格值和每个相关的最小/最大值显式捕获单独的变量:

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

  // assume the row is going to be displayed:
  var result = true; 

  // loop through the cells we want to check:
  $('#dataTable thead tr:eq(0) th').each( function (colIdx) 
    var title = $(this).text();
    if ( $(`#$title_min`).length ) 
    
      // gather all the inputs we will need to check one cell in the current row:
      var val = parseFloat(searchData[colIdx]) ||  0.0;
      var min = parseFloat($(`#$title_min`).val()) || 0;
      var max = parseFloat($(`#$title_max`).val()) || Number.MAX_VALUE;

      //console.log( min, val, max ); // just for testing

      if (val < min || val > max) 
        result = false; // any one failure means the row is filtered out
      
    
  
   );
  return result;

);

这里只有$.fn.dataTable.ext.search.push 函数发生了变化。其余代码保持不变。我试图注释代码以阐明它在做什么。我相信你可以进一步改进它,但这应该会给你一些想法。

【讨论】:

嘿@andrewjames 它的工作就像魅力一样,谢谢。但是如果我们有 20 列甚至 50 列具有相同的 min,max 过滤器怎么办?在那种情况下,我们不应该为每一列硬编码,你能建议像我在我的问题中已经做的那样,动态的东西吗? 您是否尝试过使其更适合自己?如果是这样,您尝试了什么,遇到了什么问题? (顺便说一句,我建议从最终用户的角度来看,任何具有“20 列甚至 50 列具有相同的 min、max 过滤器”的表都或多或少不可用。 ) 我刚刚注意到一件事——我很抱歉,我第一次没有发现:$.fn.dataTable.ext.search 函数应该被移动为***函数。它不应该在each 循环内。原因:我只需要将该函数推送到函数数组一次。

以上是关于如何在数据表中使用输入字段添加最小和最大范围过滤器?的主要内容,如果未能解决你的问题,请参考以下文章

reactjs中的输入过滤

如何在 devexpress 中向表单字段添加动态验证规则

如何使用范围数据注释属性指定最小但没有最大小数?

如何在python中找到输入数字的平均值、最小值、最大值和范围?

如何显示一个引导范围以及如何在输入字段中显示值?

SSRS如何在折线图上为我的x轴添加日期范围?