Angular.js ui-grid 自定义日期过滤器

Posted

技术标签:

【中文标题】Angular.js ui-grid 自定义日期过滤器【英文标题】:Angular.js ui-grid custom date filter 【发布时间】:2015-10-13 19:59:40 【问题描述】:

我正在使用位于ui-grid.info 的角度网格ui-grid。

我正在尝试制作一个自定义过滤器,该过滤器将使用日期输入控件按日期过滤网格,一个用于小于,一个用于大于。

我似乎可以在 columnDefs: field: 'mixedDate', cellFilter: 'date', filterHeaderTemplate: '<div>From <input type="date"> to <input type="date"></div>' 中使用它来获取我想要的控件。当将这些东西放在不同的范围内时,我还可以通过设置 data-ng-model="colFilter.term" 来进行某种过滤。过滤似乎甚至没有做一个 equals 。

有没有人有这方面的代码,或者可以为我指明正确的方向?

这是他们自己网站上有关该主题的一些教程,但我不太确定如何操作它们以满足我的需求,或者是否可能。

ui-grid filtering ui-grid custom filtering

【问题讨论】:

你能做一个 plnkr 来显示你的问题吗? 这是一个例子:plnkr.co/edit/R4cZa6dZllEjdHHMaHA9?p=preview。不过,我现在似乎无法让 colFilter.term 工作。它基于 ui-grid 文档中的原始示例 【参考方案1】:

你的意思是这样的吗?

首先你应该包含jQuery UI Datepicker

然后你还要为它创建一个指令:

app.directive('datePicker', function()
    return 
        restrict : "A",
        require: 'ngModel',
        link : function(scope, element, attrs, ngModel)
            $(function()
                $(element).datepicker(
                     changeMonth: true,
                     changeYear: true,
                     closeText: 'Clear',
                     showButtonPanel: true,
                     onClose: function () 
                        var event = arguments.callee.caller.caller.arguments[0];
                        // If "Clear" gets clicked, then really clear it
                        if ($(event.delegateTarget).hasClass('ui-datepicker-close')) 
                            $(this).val('');
                            scope.$apply(function() 
                               ngModel.$setViewValue(null);
                            );
                        
                    ,
                    onSelect: function(date)
                        scope.$apply(function() 
                           ngModel.$setViewValue(date);
                        );
                    
               );
            )
        
    
)

在您的 columnDefs 中,您还需要使用客户过滤器和过滤器标题模板:

filters:[ condition: checkStart, condition:checkEnd],filterHeaderTemplate: '<div class="ui-grid-filter-container">from : <input style="display:inline; width:30%" class="ui-grid-filter-input" date-picker type="text" ng-model="col.filters[0].term"/> to : <input style="display:inline; width:30%" class="ui-grid-filter-input" date-picker type="text" ng-model="col.filters[1].term"/></div>'

假设你正在使用 momentjs 过滤器功能如下:

function checkStart(term, value, row, column) 
        term = term.replace(/\\/g,"")
        var now = moment(value);
        if(term) 
            if(moment(term).isAfter(now, 'day')) return false;;
         
        return true;
    

    function checkEnd(term, value, row, column) 
        term = term.replace(/\\/g,"")
        var now = moment(value);
        if(term) 
            if(moment(term).isBefore(now, 'day')) return false;;
         
        return true;
    

【讨论】:

是的,假设过滤器实际工作正常。 checkStart 和 checkEnd 的代码在 momentjs 之外的 angularJS 中工作吗?这段代码能正常工作吗? 你能在 plnkr.co 中添加更多描述吗? 我没有测试它,因为我在给出这个答案之前就放弃了这个项目。【参考方案2】:

如果其他人正在寻找解决方案,我使用带有日期选择器的 ui-bootstrap 模式在网格标题中实现了自定义 FROMTO 过滤器。 See this plunker for details.

回想起来很明显,但找到解决方案的绊脚石之一是确保填充网格中日期列的日期值实际上是 Date 类型。事实证明,将从日期选择器中选择的日期与字符串进行比较不会让您走得太远。

注意:此解决方案依赖于 lodash 进行一些数据转换。

var app = angular.module('app', ['ngAnimate', 'ui.grid', 'ui.grid.selection', 'ui.bootstrap']);

app.controller('MainCtrl', ['$scope', '$http', 'uiGridConstants', function ($scope, $http, uiGridConstants) 

  $scope.gridOptions = 
    enableFiltering: true,
    onRegisterApi: function(gridApi)
      $scope.gridApi = gridApi;
    ,
    columnDefs: [
      
        field: 'DATE_TIME',
        displayName: 'Date Time',
        enableFiltering: true,
        enableCellEdit: false,
        filterHeaderTemplate: '<div class="ui-grid-filter-container row"><div ng-repeat="colFilter in col.filters" class="col-md-6 col-md-offset-0 col-sm-6 col-sm-offset-0 col-xs-6 col-xs-offset-0"><div custom-grid-date-filter-header></div></div></div>',
        filters: [
          
            name: 'From',
            condition: uiGridConstants.filter.GREATER_THAN_OR_EQUAL
          ,
          
            name: 'To',
            condition: uiGridConstants.filter.LESS_THAN_OR_EQUAL
          
        ],
        cellFilter: 'date:"M/d/yyyy h:mm:ss a"',
        width: '40%'
      ,
      
        field: 'QTY',
        displayName: 'Quantity',
        enableCellEdit: false,
        enableFiltering: false
      ,
      
        field: 'UNIT_COST',
        displayName: 'Unit Cost',
        enableCellEdit: false,
        enableFiltering: false
      ,
      
        field: 'TOTAL_COST',
        displayName: 'Total Cost',
        enableCellEdit: false,
        enableFiltering: false
      
    ]
  ;

  // in plnkr, grab the following data from external file
  // $http.get('grid-data.json')
  //    .success(function(data) 
  //    $scope.gridOptions.data = data;
  
  $scope.gridOptions.data = [
    
      "DATE_TIME": "2015-10-12T10:46:27.000Z",
      "QTY": 3,
      "UNIT_COST": 0.25,
      "TOTAL_COST": 0.75
    ,
    
      "DATE_TIME": "2015-10-18T06:09:27.000Z",
      "QTY": 4,
      "UNIT_COST": 0.25,
      "TOTAL_COST": 1.00
    ,
    
      "DATE_TIME": "2015-10-05T11:57:27.000Z",
      "QTY": 6,
      "UNIT_COST": 0.55,
      "TOTAL_COST": 0.90
    ,
    
      "DATE_TIME": "2015-10-21T03:42:27.000Z",
      "QTY": 8,
      "UNIT_COST": 0.25,
      "TOTAL_COST": 2.00
    ,
    
      "DATE_TIME": "2015-09-29T18:25:27.000Z",
      "QTY": 3,
      "UNIT_COST": 0.45,
      "TOTAL_COST": 1.35
    ,
    
      "DATE_TIME": "2015-09-19T21:13:27.000Z",
      "QTY": 5,
      "UNIT_COST": 0.25,
      "TOTAL_COST": 1.25
    ,
    
      "DATE_TIME": "2015-08-31T15:46:27.000Z",
      "QTY": 7,
      "UNIT_COST": 0.10,
      "TOTAL_COST": 0.70
    ,
    
      "DATE_TIME": "2015-10-12T10:14:27.000Z",
      "QTY": 2,
      "UNIT_COST": 0.65,
      "TOTAL_COST": 1.30
    
  ];

  // make sure date values are Date objects
  _.forEach($scope.gridOptions.data, function (val) 
    val.DATE_TIME = new Date(val.DATE_TIME);
  );

])

.controller('gridDatePickerFilterCtrl', ['$scope', '$timeout', '$uibModal', 'uiGridConstants', function( $scope, $timeout, $uibModal, uiGridConstants) 

  $timeout(function() 
    console.log($scope.col); 
    var field = $scope.col.colDef.name;

    var allDates = _.map($scope.col.grid.appScope.gridOptions.data, function(datum) 
      return datum[field];
    );
      
    var minDate = _.min(allDates);
    var maxDate = _.max(allDates);

    $scope.openDatePicker = function(filter) 
      
      var modalInstance = $uibModal.open(
        templateUrl: 'custom-date-filter.html',
        controller: 'customGridDateFilterModalCtrl as custom',
        size: 'md',
        windowClass: 'custom-date-filter-modal',
        resolve: 
          filterName: [function() 
            return filter.name;
          ],
          minDate: [function() 
            return new Date(minDate);
          ],
          maxDate: [function() 
            return new Date(maxDate);
          ],
        
      );
  
      modalInstance.result.then(function(selectedDate) 
        
        console.log('date', selectedDate);
        $scope.colFilter.listTerm = [];
        
        console.log(typeof selectedDate);
        console.log(selectedDate instanceof Date);
        
        $scope.colFilter.term = selectedDate;
      );
    ;
      
  );
  

])
.controller('customGridDateFilterModalCtrl', ['$scope', '$rootScope', '$log', '$uibModalInstance', 'filterName', 'minDate', 'maxDate', function($scope, $rootScope, $log, $uibModalInstance, filterName, minDate, maxDate) 
  
    var ctrl = this;

    console.log('filter name', filterName);
    console.log('min date', minDate, 'max date', maxDate);
    
    ctrl.title = 'Select Dates ' + filterName + '...';
    ctrl.minDate = minDate;
    ctrl.maxDate = maxDate;
    ctrl.customDateFilterForm;
  
    ctrl.filterDate = (filterName.indexOf('From') !== -1) ? angular.copy(ctrl.minDate) : angular.copy(ctrl.maxDate);
    
    function setDateToStartOfDay(date) 
      return new Date(date.getFullYear(), date.getMonth(), date.getDate());
    

    function setDateToEndOfDay(date) 
      return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
    

    ctrl.filterDateChanged = function () 
      ctrl.filterDate = (filterName.indexOf('From') !== -1) ? setDateToStartOfDay(ctrl.filterDate) : setDateToEndOfDay(ctrl.filterDate);
      $log.log('new filter date', ctrl.filterDate);
    ;
    
    ctrl.setFilterDate = function(date) 
      $uibModalInstance.close(date);
    ;

    ctrl.cancelDateFilter = function() 
      $uibModalInstance.dismiss();
    ;
  
])

.directive('customGridDateFilterHeader', function() 
  return 
    template: '<button class="btn btn-default date-time-filter-buttons" style="width:90%;padding:inherit;" ng-click="openDatePicker(colFilter)"> colFilter.name </button><div role="button" class="ui-grid-filter-button-select cancel-custom-date-range-filter-button ng-scope" ng-click="removeFilter(colFilter, $index)" ng-if="!colFilter.disableCancelFilterButton" ng-disabled="colFilter.term === undefined || colFilter.term === null || colFilter.term === \'\'" ng-show="colFilter.term !== undefined &amp;&amp; colFilter.term != null" tabindex="0" aria-hidden="false" aria-disabled="false" style=""><i class="ui-grid-icon-cancel cancel-custom-date-range-filter" ui-grid-one-bind-aria-label="aria.removeFilter" aria-label="Remove Filter">&nbsp;</i></div>',
    controller: 'gridDatePickerFilterCtrl'
  ;
)
;
<!DOCTYPE html>
<html ng-app="app">

  <head>
    <script src="https://cdn.jsdelivr.net/lodash/4.6.1/lodash.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-animate.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.3.2/ui-bootstrap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.3.2/ui-bootstrap-tpls.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.7/angular-material.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.1.1/ui-grid.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.1.1/ui-grid.min.css" type="text/css" />
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.7/angular-material.min.css" />
    <link data-require="bootstrap-css@*" data-semver="3.3.6" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" />
    <script src="script.js"></script>
  </head>

  <body> 
    
    <div ng-controller="MainCtrl">
      <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    </div>
    
    <script type="text/ng-template" id="custom-date-filter.html">
    
      <div class="col-md-12 col-md-offset-0 col-sm-12 col-sm-offset-0 col-xs-12 col-xs-offset-0">
  
        <div class="modal-header">
          <p class="modal-title well custom-date-filter-header">
            <span class="custom-date-filter-title-text">
               custom.title 
            </span>
          </p>
        </div>
  
        <div class="row modal-body custom-date-filter-container-row">
  
          <form name="custom.customDateFilterForm"
                ng-submit="custom.setFilterDate(custom.filterDate)"
                no-validation>

            <div class="row custom-filter-date-input-row">
            
              <div class="well col-md-8 col-md-offset-2 col-sm-8 col-sm-offset-2 col-xs-10 col-xs-offset-1 custom-date-filter-input">
              
                <uib-datepicker ng-model="custom.filterDate" 
                    min-date="custom.minDate" 
                    max-date="custom.maxDate"
                    ng-change="custom.filterDateChanged()"
                    class="well well-sm">
                </uib-datepicker>

              </div>

            </div>

            <div class="row modal-footer custom-date-filter-submit-buttons-row">

              <div class="custom-date-filter-submit-buttons-div col-lg-8 col-lg-offset-2 col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 col-xs-10 col-xs-offset-1">

                <button class="btn btn-success btn-lg custom-date-filter-submit-button"
                        type="submit">
                  Apply
                </button>

                <button type="button"
                        class="btn btn-warning btn-lg custom-date-filter-cancel-button"
                        ng-click="custom.cancelDateFilter()">
                  Cancel
                </button>

              </div>

            </div>

          </form>
  
        </div>
  
      </div>
    
    </script>
  </body>

</html>

【讨论】:

上述日期范围过滤器我试图实现其工作正常。谢谢你的好工作。目前我只需要一个输入元素,其中 from calendar date 和 to date calendar 应该在一个弹出窗口中。【参考方案3】:

我正在使用 angular-ui-grid 3.1.1 和 angular-ui-bootstrap 1.3.2。

我的解决方案基于ui-grid filter help 和 Munna S / Bennett Adams cmets。我用更少的代码获得了一个解决方案。

它适用于两个过滤器和一个自定义模板 ('ui-grid/custom-ui-grid-filter')。

   field: 'DATE_TIME', name: 'Date Time', cellTooltip: true,
    cellFilter: 'date:\'yyyy-MM-dd\'',
    cellTemplate: 'ui-grid/date-cell',
    filterHeaderTemplate: 'ui-grid/custom-ui-grid-filter',
    width: '40%',
    filters: [
        
          condition: function(term, value, row, column)
                if (!term) return true;
                var valueDate = new Date(value);
                return valueDate >= term;
            ,
          placeholder: 'Greater than or equal'
        ,
        
          condition: function(term, value, row, column)
                if (!term) return true;
                var valueDate = new Date(value);
                return valueDate <= term;
            ,
          placeholder: 'Less than or equal'
        
    ],
    headerCellClass: $scope.highlightFilteredHeader 

请记住,在条件函数中,“term”来自 DatePicker 过滤器并且是一个日期。此外,在我的示例中,value 是格式为“yyyy-MM-dd”的字符串。

这是我的Plunkr 希望对您有所帮助,如果您有任何改进,请告诉我。

【讨论】:

我需要相同的过滤器,但在网格“自定义”之外,而不是内部网格单元过滤器。请帮助我如何分配 minDate 和 maxDate 以从对象中过滤? 太好了,效果很好。另外,ui-grid div标签没有变化,只是添加一些js。 这应该是目前为止最好的解决方案。【参考方案4】:

我已经使用自定义 javascript 方法完成了它

condition: function(term, value)
    if (!term) return true;
    var valueDate = new Date(value);
    var replaced = term.replace(/\\/g,'');
    var termDate = new Date(replaced);
    return valueDate < termDate;
,
placeholder: 'less than'

【讨论】:

对于更多与浏览器无关的解决方案,我将切换到 valueDate.getTime() ***.com/questions/338463/… 您可能还需要尝试、捕获或检查无效日期。

以上是关于Angular.js ui-grid 自定义日期过滤器的主要内容,如果未能解决你的问题,请参考以下文章

Angular JS 自定义分隔符

angular js 自定义添加依赖

Angular JS 'Startswith' 自定义过滤器

angular js自定义service的简单示例

Angular-Gantt - 可以将日期的标题更改为“M,T,W,Th ...”而不是日期?

angular.js创建自定义指令-demo3