将数字范围过滤器添加到多个DataTable列

时间:2020-07-21 15:40:17

标签: javascript jquery datatables bootstrap-slider

我有一个DataTable,我正在尝试向其中的多个列添加过滤器。有些列是字符串,需要文本输入,而另一些是数字,需要范围输入。我将过滤器添加到每一列as described here。对于范围输入,我尝试添加自己的自定义搜索插件as described here。本质上,我试图结合文档两部分中的策略:我想遍历应用过滤器的每一列,对于那些数值的列,我想使用范围过滤器。他们在多列过滤文档中提供的示例表包括数字列,但用于这些列的过滤器是文本输入,坦率地说,在现实世界中,这似乎并不是大多数人采用的方式。他们提供的用于设置数值范围过滤器的文档包括一个示例,该示例仅包含一个要由输入过滤的列,这使他们可以将相应的列索引硬编码到其自定义函数中。

我的问题是我不知道如何将所需的变量获取到自定义范围过滤器函数中。具体来说,我需要获取列索引和用户输入到函数中。我将this bootstrap slider用于范围输入,因此为了获取用户输入值,我在输入上调用.slider并传入'getValue'

如何将我的变量(特别是列索引和用户输入)放入我的自定义范围过滤器函数中?

我的代码如下。我还制作了这个JSFiddle,以显示我要执行的操作。请注意,如果您注释掉自定义DataTables函数,则两种文本输入是如何工作的。

function populateEntryTable() {
    $('#entryTableContainer').empty();
    /* put demo data in array of objects that is used to populate DataTable */
    var entries = [{name: John, age: 20, salary: 40000},
     {name: Bill, age: 40, salary: 200000},
     {name: Amy, age: 31, salary: 150000}];

    /*build my table*/
    $('#entryTableContainer').append('<table id="entryTable"><thead><tr></tr></thead><tbody></tbody></table>');
    for (var key in entries[0]) {
        $('#entryTableContainer thead tr').append('<th>' + key + '</th>');
    }
    for (var i = entries.length - 1; i >= 0; i--) {
        for (var key in entries[i]) {
            $('#entryTableContainer tbody tr:last-child').append('<td>' + entries[i][key] + '</td>');
        }
    }

    /* add column filters below each column, as described in DataTables documentation */
    $('#entryTable thead tr').clone(true).appendTo('#entryTable thead');
    var numberInputs = ['age','salary'];
    $('#entryTable thead tr:eq(1) th').each(function(i) {
        var title = $(this).text();
            /* if the col requires a text input filter, do text input filter stuff, which works fine. Else if it requires a number range filter, do number filter stuff, which doesn't work fine. */
            if (numberInputs.indexOf(title) == -1) {
              $(this).html('<input type="text" placeholder="Search">');
              $('input',this).on('keyup change',function() {
                if (entryTable.column(i).search() !== this.value) {
                    entryTable.column(i).search(this.value).draw();
                }
            });
        } else if (numberInputs.indexOf(title) > -1) {
        /* get min and max values in each column to set appropriate bootstrap-slider attributes */
            var min;
            var max;
            $('#entryTable tbody tr').each(function(j) {
                var item = parseFloat($('#entryTable tbody tr:eq(' + j + ') td:eq(' + i + ')').text());
                if (min == undefined || item < min) {
                    min = Math.floor(item);
                }
                if (max == undefined || item > max) {
                    max = Math.ceil(item);
                }
            });
        
        /* create bootstrap-slider with double inputs */
            $(this).html('<input id="' + title + '" data-slider-min="' + min + '" data-slider-max="' + max + '" data-slider-step="1" data-slider-value="[' + min + ',' + max + ']">');
            $('#' + title).slider({});
        
        /* add listener for bootstrap-slider change */
            $('input',this).on('change',function() {
            /* returns an array with the min and max user inputs*/
               var userInputs = $(this).slider('getValue');
               var userMin = userInputs[0];
               var userMax = userInputs[1];
               entryTable.draw();
            });
        }
    });

    /* call DataTable on my table and include my option settings*/
    var entryTable = $('#entryTable').DataTable({
        orderCellsTop: true,
        paging: false,
        bInfo: false,
        scrollY: 400,
        scrollCollapse: true,
        order: [ 1, 'desc' ],
        searching: true
    });

    /* searching must be set to true for my column searches to work, but I don't want the whole table search bar to display, so I remove it here */
    $('#entryTable_filter').addClass('d-none');
}

// custom DataTables function for filtering number ranges
$.fn.dataTable.ext.search.push(
    function( settings, data, dataIndex ) {
        /* how do I get i (the col index of the filter that the user is engaging with), the userMin and the userMax into here??? */
        var colVal = parseFloat(data[i].replace('$','')) || 0;
 
        if ( ( isNaN( userMin ) && isNaN( userMax ) ) ||
             ( isNaN( userMin ) && colVal <= userMax ) ||
             ( userMin <= colVal   && isNaN( userMax ) ) ||
             ( userMin <= colVal   && colVal <= userMax ) )
        {
            return true;
        }
        return false;
    }
);

1 个答案:

答案 0 :(得分:1)

通过在.each循环内移动自定义函数,将所需的变量引入适当的范围,我能够解决我的问题。我将解决方案放在JSFiddle上。

    $(function() {
  populateEntryTable()

  function populateEntryTable() {
    $('#entryTableContainer').empty();
    /* put demo data in array of objects that is used to populate DataTable */
    var entries = [{
        name: 'John',
        title: 'Coordinator',
        age: 20,
        salary: 40000
      },
      {
        name: 'Bill',
        title: 'Manager',
        age: 40,
        salary: 200000
      },
      {
        name: 'Amy',
        title: 'Manager',
        age: 31,
        salary: 150000
      }
    ];

    /*build my table*/
    $('#entryTableContainer').append('<table id="entryTable"><thead><tr></tr></thead><tbody></tbody></table>');
    for (var key in entries[0]) {
      $('#entryTable thead tr').append('<th>' + key + '</th>');
    }
    for (var i = entries.length - 1; i >= 0; i--) {
      $('#entryTable tbody').append('<tr></tr>');
      for (var key in entries[i]) {
        $('#entryTable tbody tr:last-child').append('<td>' + entries[i][key] + '</td>');
      }
    }

    $('#entryTable thead tr').clone(true).appendTo('#entryTable thead');
    var numberInputs = ['age', 'salary'];
    $('#entryTable thead tr:eq(1) th').each(function(i) {
      var title = $(this).text();
      // if the col requires a text input filter, do text input filter stuff, which works fine. Else if it requires a number range filter, do number filter stuff, which doesn't work fine.
      if (numberInputs.indexOf(title) == -1) {
        $(this).html('<input type="text" placeholder="Search">');
        $('input', this).on('keyup change', function() {
          if (entryTable.column(i).search() !== this.value) {
            entryTable.column(i).search(this.value).draw();
          }
        });
      } else if (numberInputs.indexOf(title) > -1) {
        // get min and max values in each column to set appropriate bootstrap-slider attributes
        var min;
        var max;
        $('#entryTable tbody tr').each(function(j) {
          var item = parseFloat($('#entryTable tbody tr:eq(' + j + ') td:eq(' + i + ')').text());
          if (min == undefined || item < min) {
            min = Math.floor(item);
          }
          if (max == undefined || item > max) {
            max = Math.ceil(item);
          }
        });

        var rangeMax = title == 'age' ? 100 : 1000000;
        var step = rangeMax == 100 ? 1 : 10000;
        $(this).html('<input id="' + title + '" type="range" value="0" min="0" max="' + rangeMax + '" step="' + step + '">');
        var userInput = $('input', this).val();

        // custom DataTables function for filtering number ranges
        $.fn.dataTable.ext.search.push(
          function(settings, data, dataIndex) {
            var colVal = parseFloat(data[i]) || 0;
            if (colVal > userInput) {
              return true;
            }
            return false;
          }
        );

        // add listener for bootstrap-slider change
        $('input', this).on('change', function() {
          userInput = $(this).val();
          entryTable.draw();
        });
      }
    });
    /* call DataTable on my table and include my option settings */
    var entryTable = $('#entryTable').DataTable({
      orderCellsTop: true,
      paging: false,
      bInfo: false,
      scrollY: 400,
      scrollCollapse: true,
      order: [1, 'desc'],
      searching: true
    });
    /*     hide whole table search bar--cannot set 'searching' to false because this also disables individual column search capabilities */
    $('#entryTable_filter').hide();
  }
});
相关问题