DataTables+Datepicker 按日期范围过滤表格

Posted

技术标签:

【中文标题】DataTables+Datepicker 按日期范围过滤表格【英文标题】:DataTables+Datepicker filter table by date range 【发布时间】:2019-07-08 13:38:59 【问题描述】:

尝试使用两个有界日期选择器按日期范围实现 DataTables 过滤器。

我在 SO 上看到的类似问题很少,但没有一个对我有用。

到目前为止,我设法实现了界面元素,但不知道如何将它们组合在一起以进一步进行。任何帮助表示赞赏。

var myTableData = 
  [
    
      "id": "1",
      "name": "Tiger Nixon",
      "position": "System Architect",
      "salary": "$320,800",
      "start_date": "2011/04/25",
      "office": "Edinburgh",
      "extn": "5421"
    ,
    
      "id": "2",
      "name": "Garrett Winters",
      "position": "Accountant",
      "salary": "$170,750",
      "start_date": "2011/07/25",
      "office": "Tokyo",
      "extn": "8422"
    ,
    
      "id": "3",
      "name": "Ashton Cox",
      "position": "Junior Technical Author",
      "salary": "$86,000",
      "start_date": "2009/01/12",
      "office": "San Francisco",
      "extn": "1562"
    ,
    
      "id": "4",
      "name": "Cedric Kelly",
      "position": "Senior javascript Developer",
      "salary": "$433,060",
      "start_date": "2012/03/29",
      "office": "Edinburgh",
      "extn": "6224"
    ,
    
      "id": "5",
      "name": "Airi Satou",
      "position": "Accountant",
      "salary": "$162,700",
      "start_date": "2008/11/28",
      "office": "Tokyo",
      "extn": "5407"
    ,
    
      "id": "6",
      "name": "Brielle Williamson",
      "position": "Integration Specialist",
      "salary": "$372,000",
      "start_date": "2012/12/02",
      "office": "New York",
      "extn": "4804"
    ,
    
      "id": "7",
      "name": "Herrod Chandler",
      "position": "Sales Assistant",
      "salary": "$137,500",
      "start_date": "2012/08/06",
      "office": "San Francisco",
      "extn": "9608"
    
];

$('.datepicker').datepicker();

var myDataTable = $('#staff').DataTable(
  sDom: 't',
  data: myTableData,
  columns: [
    title: 'Name', data: 'name',
    title: 'Position', data: 'position',
    title: 'Office', data: 'office',
    title: 'Hire date', data: 'start_date',
    title: 'Salary', data: 'salary'
  ]
);
<!doctype html>
<html>
  <head>
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
    <link rel="stylesheet" type="text/css" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script type="application/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <script type="application/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
  </head>
  <body>
    <label>Start date:</label>
    <input id="startdate" class="datepicker"></input>
    <label>End date:</label>
    <input id="enddate" class="datepicker"></input>
    <button id="filter">Filter</button>
    <table id="staff"></table>
  </body>
</html>

【问题讨论】:

【参考方案1】:

我对您的代码做了一些修改。请参阅下面 JavaScript sn-p 中的 cmets,其中大部分位于底部,在您的 var myDataTable = $('#staff').DataTable() 声明下:

// I changed some of the start_date values to be more recent, just for testing.
var myTableData = [
    "id": "1",
    "name": "Tiger Nixon",
    "position": "System Architect",
    "salary": "$320,800",
    "start_date": "2017/04/25",
    "office": "Edinburgh",
    "extn": "5421"
  ,
  
    "id": "2",
    "name": "Garrett Winters",
    "position": "Accountant",
    "salary": "$170,750",
    "start_date": "2018/07/25",
    "office": "Tokyo",
    "extn": "8422"
  ,
  
    "id": "3",
    "name": "Ashton Cox",
    "position": "Junior Technical Author",
    "salary": "$86,000",
    "start_date": "2019/01/12",
    "office": "San Francisco",
    "extn": "1562"
  ,
  
    "id": "4",
    "name": "Cedric Kelly",
    "position": "Senior Javascript Developer",
    "salary": "$433,060",
    "start_date": "2018/03/29",
    "office": "Edinburgh",
    "extn": "6224"
  ,
  
    "id": "5",
    "name": "Airi Satou",
    "position": "Accountant",
    "salary": "$162,700",
    "start_date": "2018/11/28",
    "office": "Tokyo",
    "extn": "5407"
  ,
  
    "id": "6",
    "name": "Brielle Williamson",
    "position": "Integration Specialist",
    "salary": "$372,000",
    "start_date": "2018/12/02",
    "office": "New York",
    "extn": "4804"
  ,
  
    "id": "7",
    "name": "Herrod Chandler",
    "position": "Sales Assistant",
    "salary": "$137,500",
    "start_date": "2018/08/06",
    "office": "San Francisco",
    "extn": "9608"
  
];

var myDataTable = $('#staff').DataTable(
  sDom: 't',
  data: myTableData,
  columns: [
      title: 'Name',
      data: 'name'
    ,
    
      title: 'Position',
      data: 'position'
    ,
    
      title: 'Office',
      data: 'office'
    ,
    
      title: 'Hire date',
      data: 'start_date'
    ,
    
      title: 'Salary',
      data: 'salary'
    
  ]
);

// I instantiate the two datepickers here, instead of all at once like before.
// I also changed the dateFormat to match the format of the dates in the data table.
$("#startdate").datepicker(
  "dateFormat": "yy/mm/dd",
  "onSelect": function(date)   // This handler kicks off the filtering.
    minDateFilter = new Date(date).getTime();
    myDataTable.draw(); // Redraw the table with the filtered data.
  
).keyup(function() 
  minDateFilter = new Date(this.value).getTime();
  myDataTable.draw();
);

$("#enddate").datepicker(
  "dateFormat": "yy/mm/dd",
  "onSelect": function(date) 
    maxDateFilter = new Date(date).getTime();
    myDataTable.draw();
  
).keyup(function() 
  maxDateFilter = new Date(this.value).getTime();
  myDataTable.draw();
);

// The below code actually does the date filtering.
minDateFilter = "";
maxDateFilter = "";

$.fn.dataTableExt.afnFiltering.push(
  function(oSettings, aData, iDataIndex) 
    if (typeof aData._date == 'undefined') 
      aData._date = new Date(aData[3]).getTime(); // Your date column is 3, hence aData[3].
    

    if (minDateFilter && !isNaN(minDateFilter)) 
      if (aData._date < minDateFilter) 
        return false;
      
    

    if (maxDateFilter && !isNaN(maxDateFilter)) 
      if (aData._date > maxDateFilter) 
        return false;
      
    

    return true;
  
);
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
<link rel="stylesheet" type="text/css" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="application/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script type="application/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<label>Start date:</label>
<input id="startdate" class="date_range_filter" />
<label>End date:</label>
<input id="enddate" class="date_range_filter" />
<table id="staff"></table>

我还删除了“过滤器”按钮,因为在此实现中不需要它。当您从日期选择器中选择一个日期时,表格应该会自动更新。

【讨论】:

【参考方案2】:

您的(稍作修改)示例具有一定的附加值(独立于时区、有限的年份范围、有界的日期选择器):

//Data definition
var myTableData =
  [
    "id": "1",
    "name": "Tiger Nixon",
    "position": "System Architect",
    "salary": "$320,800",
    "start_date": "2011/04/25",
    "office": "Edinburgh",
    "extn": "5421"
  , 
    "id": "2",
    "name": "Garrett Winters",
    "position": "Accountant",
    "salary": "$170,750",
    "start_date": "2011/07/25",
    "office": "Tokyo",
    "extn": "8422"
  , 
    "id": "3",
    "name": "Ashton Cox",
    "position": "Junior Technical Author",
    "salary": "$86,000",
    "start_date": "2009/01/12",
    "office": "San Francisco",
    "extn": "1562"
  , 
    "id": "4",
    "name": "Cedric Kelly",
    "position": "Senior Javascript Developer",
    "salary": "$433,060",
    "start_date": "2012/03/29",
    "office": "Edinburgh",
    "extn": "6224"
  , 
    "id": "5",
    "name": "Airi Satou",
    "position": "Accountant",
    "salary": "$162,700",
    "start_date": "2008/11/28",
    "office": "Tokyo",
    "extn": "5407"
  , 
    "id": "6",
    "name": "Brielle Williamson",
    "position": "Integration Specialist",
    "salary": "$372,000",
    "start_date": "2012/12/02",
    "office": "New York",
    "extn": "4804"
  , 
    "id": "7",
    "name": "Herrod Chandler",
    "position": "Sales Assistant",
    "salary": "$137,500",
    "start_date": "2012/08/06",
    "office": "San Francisco",
    "extn": "9608"
  
];
//Global variable for future use
var datepickers = [
    id: 'startdate',
    coid: 'enddate',
    value: null,
    limiter: 'minDate'
  , 
    id: 'enddate',
    coid: 'startdate',
    value: null,
    limiter: 'maxDate'
  
];
//Translate 'yy/mm/dd' string to UTC date
const yymmddUTC = str => new Date(...str.split('/').map((value,index) => index == 1 ? value-- : value));
//DataTables object definition
var myDataTable = $('#staff').DataTable(
    sDom: 't',
    data: myTableData,
    columns: [
        title: 'Name',
        data: 'name'
      , 
        title: 'Position',
        data: 'position'
      , 
        title: 'Office',
        data: 'office'
      , 
        title: 'Hire date',
        data: 'start_date'
      , 
        title: 'Salary',
        data: 'salary'
      
    ]
  );
//Limit datepicker options to those valid for current dataset
var dates = myDataTable.column(3).data().unique().sort();
var minDate = dates[0];
var maxDate = dates[dates.length-1];
//datepicker objects definition
$('.datepicker').datepicker(
  dateFormat: 'yy/mm/dd',
  changeMonth: true,
  defaultDate: minDate,
  changeYear: true,
  yearRange: minDate.substr(0,4)+':'+maxDate.substr(0,4),
  onSelect: function (selectedDate) 
    let datepicker = datepickers.find(entry => entry.id == $(this).attr('id'));
    $(`#$datepicker.coid`).datepicker('option', datepicker.limiter, selectedDate);
    datepicker.value = yymmddUTC(selectedDate);
    myDataTable.draw();
  
).on('change', function()
  datepickers[datepickers.findIndex(item => item.id == $(this).attr('id'))].value = yymmddUTC($(this).val());
  myDataTable.draw();
);
//External search function
$.fn.DataTable.ext.search.push((settings, row) => 
  let rowDate = yymmddUTC(row[3]);
  return (rowDate >= datepickers[0].value || datepickers[0].value == null) && (rowDate <= datepickers[1].value || datepickers[1].value == null);
);
<!doctype html>
<html>
  <head>
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
    <link rel="stylesheet" type="text/css" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script type="application/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <script type="application/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
  </head>
  <body>
    <label>Start date:</label>
    <input id="startdate" class="datepicker"></input>
    <label>End date:</label>
    <input id="enddate" class="datepicker"></input>
    <table id="staff"></table>
  </body>
</html>

【讨论】:

如果日期在数据表中为yyyy-mm-dd h:i:s 格式,我需要仅使用yyyy-mm-dd 进行搜索,而在数据表中显示格式为yyyy-mm-dd h:i:s 时如何执行此操作?任何建议都会有很大帮助。提前致谢。 @Curr195 我省略了 yymmddUTC 函数的使用,并使用@androidNoobie 的方法来获取时间格式与getTime() 代替您的日期过滤,因为我的日期时间为yy-mm-dd h:i:s 格式我遇到了一些困难无论如何,一开始@Cur195 和@AndroidNoobie 的回答都有助于完成工作。非常感谢 有一件事,在 chrome 中,日期选择器的输入字段显示以前选择的日期,如下拉列表,这很烦人,有什么提示可以解决这个问题吗?另外,我如何在过滤一次后取消选择日期并返回上一个完整列表? (对不起,如果这很烦人,但如果这与这个答案无关,会发布一个不同的问题。)【参考方案3】:

您必须添加此代码部分以获取日期范围和雇用日期。

    $(document).ready(function()
     $.fn.dataTable.ext.search.push(
     function (settings, data, dataIndex) 
        var min = $('#startdate').datepicker("getDate");
        var max = $('#enddate').datepicker("getDate");
        var hireDate = new Date(data[3]);
        if (min == null && max == null)  return true; 
        if (min == null && hireDate <= max)  return true;
        if(max == null && hireDate >= min) return true;
        if (hireDate <= max && hireDate >= min)  return true; 
        return false;
    
    );
    );

而且你必须为你的按钮点击事件。

$("#filter").click(function () 

    var myDataTable = $('#staff').DataTable();
        myDataTable.draw();
);

第一部分获取日期,第二部分再次绘制数据表。

【讨论】:

以上是关于DataTables+Datepicker 按日期范围过滤表格的主要内容,如果未能解决你的问题,请参考以下文章

jQuery DataTables - 按隐藏列排序日期

自定义按值的日期部分对 DataTables 列进行排序

来自 Ajax 源的 DataTables 按数据顺序排序并显示格式化日期

DataTables:按纪元时间排序

时间日期事件处理,长按事件

angular-ui datepicker datepicker 的初始状态不是按 datepicker-popup 格式化的