如何将datetimepicker js包装到AngularJS指令中

时间:2014-03-29 08:00:29

标签: javascript angularjs twitter-bootstrap

我花了一些时间研究angularjs的现有datetime指令。

ngularUI和AngularStrap都不提供我需要的datetimepicker。当然,我知道使用datepicker和timepicker来归档目的。

我从互联网和stackoverflow搜索了相关主题。找到了一些有趣且有用的信息。

http://dalelotts.github.io/angular-bootstrap-datetimepicker/,有一个datetimepicker,但我不喜欢这个指令的用法。

connecting datetimepicker to angularjs,这个主题非常有用,我尝试按照步骤包装我的datetimepicker指令。

我的工作基于https://github.com/Eonasdan/bootstrap-datetimepicker,一个基于bootstrap 3的datetimepicker,用户界面非常好。

app.directive('datetimepicker', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attrs, ngModelCtrl) {
            console.log('call datetimepicker link...');
            var picker = element.datetimepicker({
                dateFormat: 'dd/MM/yyyy hh:mm:ss'
            });

            //ngModelCtrl.$setViewValue(picker.getDate());

            //model->view
            ngModelCtrl.$render(function() {
                console.log('ngModelCtrl.$viewValue@'+ngModelCtrl.$viewValue);
                picker.setDate(ngModelCtrl.$viewValue || '');
            });

            //view->model
            picker.on('dp.change', function(e) {
                console.log('dp.change'+e.date);              
                scope.$apply(function(){
                    ngModelCtrl.$setViewValue(e.date);
                });
            });
        }
    };
});

并在我看来使用它。

<div class="col-md-6">
  <div class="input-group date" id="endTime" data-datetimepicker  ng-model="stat.endTime" data-date-format="MM/DD/YYYY hh:mm A/PM" >
    <input class="form-control" type="text" placeholder="End"/>
    <span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span>
    </span>
  </div>
</div>

我发现了一些问题。

  1. 如果在视图中渲染之前通过json设置了日期,则初始日期没有显示,我看不到任何执行ngModel渲染方法的日志。
  2. 当我选择一个日期时,它为json数据提供了一个基于字符串的日期时间,而不是长格式。在视图中的其他相关片段中,基于字符串的日期无法通过角度日期过滤器进行解析。
  3. 在模态对话框中使用它时,下次弹出模态窗口时不会清除它的值。
  4. 提前致谢。

7 个答案:

答案 0 :(得分:4)

我有同样的问题。以下是我最终做的对我有用的事情:

'use strict';

angular.module('frontStreetApp.directives')
    .directive('psDatetimePicker', function (moment) {
        var format = 'MM/DD/YYYY hh:mm A';

        return {
            restrict: 'A',
            require: 'ngModel',
            link: function (scope, element, attributes, ctrl) {
                element.datetimepicker({
                    format: format
                });
                var picker = element.data("DateTimePicker");

                ctrl.$formatters.push(function (value) {
                    var date = moment(value);
                    if (date.isValid()) {
                        return date.format(format);
                    }
                    return '';
                });

                element.on('change', function (event) {
                    scope.$apply(function() {
                        var date = picker.getDate();
                        ctrl.$setViewValue(date.valueOf());
                    });
                });
            }
        };
    });

这是HTML:

<!-- The dueDate field is a UNIX offset of the date -->
<input type="text"
       ng-model="dueDate"
       ps-datetime-picker
       class="form-control">

您可以查看要点和更多信息in my blog post

答案 1 :(得分:1)

Eonasdan日期时间选择器我真的很努力。在网上发布的大多数解决方案都可以正常工作 - 所以没问题。

最后,我合并了一些我在网上找到的解决方案。我将它包裹在一个工作的plunker中: http://plnkr.co/n8L8UZ

该指令使用ng-model格式的moment工作,更多的是它允许传递两个函数: onDateChangeFunctiononDateClickFunction分别被调用。

快乐使用!

指令源代码:

angular
    .module('plunker')
    .directive('datetimepicker', [
      '$timeout',
      function($timeout) {
        return {
          require: '?ngModel',
          restrict: 'EA',
          scope: {
            datetimepickerOptions: '@',
            onDateChangeFunction: '&',
            onDateClickFunction: '&'
          },
          link: function($scope, $element, $attrs, controller) {
            $element.on('dp.change', function() {
              $timeout(function() {
                var dtp = $element.data('DateTimePicker');
                controller.$setViewValue(dtp.date());
                $scope.onDateChangeFunction();
              });
            });

            $element.on('click', function() {
              $scope.onDateClickFunction();
            });

            controller.$render = function() {
              if (!!controller && !!controller.$viewValue) {
                var result = controller.$viewValue;
                $element.data('DateTimePicker').date(result);
              }
            };

            $element.datetimepicker($scope.$eval($attrs.datetimepickerOptions));
          }
        };
      }
    ]);

答案 2 :(得分:0)

可以帮助你提出第一点;将 $ watch 添加到链接功能中的元素,并在文本字段中设置

 value="{{$scope.variableWithTheInitialDate}}" 
;加载时,datetimepicker将被设置。
对于第二点,我使用 moment.js 但是没有尝试过你的例子来告诉你如何:-P 祝你好运!

答案 3 :(得分:0)

问题1的可能解决方案:

您需要通过执行以下操作,将视图值从头开始设置为模型中的日期:

if (ngModel.$viewValue) {

  picker.data("DateTimePicker").setDate(new Date(ngModel.$modelValue));'

  picker.on('change', function(e) {

    ....

  });

}

答案 4 :(得分:0)

要完成cdmckay's solution以便使用ng-model的值正确初始化日期时间选择器窗口小部件,我在dp.show事件上添加了一个监听器。所以,我的解决方案是:

'use strict';

angular.module('frontStreetApp.directives', [])
  .directive('psDatetimePicker', function (moment) {
      var format = 'MM/DD/YYYY hh:mm A';

      return {
          restrict: 'A',
          require: 'ngModel',
          link: function (scope, element, attributes, ctrl) {
              element.datetimepicker({
                  format: format
              });
              var picker = element.data("DateTimePicker");

              ctrl.$formatters.push(function (value) {
                  var date = moment(value);
                  if (date.isValid()) {
                      return date.format(format);
                  }
                  return '';
              });

              /**
              * Update datetime picker's value from ng-model when opening the datetime picker's dropdown
              */
              element.on('dp.show', function() {
                  picker.setDate(ctrl.$viewValue);
              });

              /**
              * Update ng-model when  datetime picker's value changes
              */
              element.on('change', function (event) {
                  scope.$apply(function () {
                      var date = picker.getDate();
                      ctrl.$setViewValue(date);
                  });
              });
          }
      };
  });

答案 5 :(得分:0)

我最终把输入放在div中并将模型绑定到那个。它还包括bootstrapvalidator(对不起,我没有时间让代码完美,但你应该明白这一点)

示例HTML代码:

<div datetimepicker="{pickTime: false}" data-ng-model="model.Birthday"><input type="text" name="Birthday" class="form-control" data-date-format="YYYY/MM/DD" data-mask="0000/00/00" data-bv-date="true" data-bv-date-format="YYYY/MM/DD" /></div>

和javascript代码:

app.directive('datetimepicker', function ($timeout) {
return {
    // Restrict it to be an attribute in this case
    restrict: 'AE',
    // optionally hook-in to ngModel's API 
    require: '?ngModel',
    // responsible for registering DOM listeners as well as updating the DOM
    link: function ($scope, element, $attrs, ngModel) {
        var $element;
        $timeout(function () {

            $element = $(element).find("input").datetimepicker($scope.$eval($attrs.datetimepicker));

            var DateTimePicker = $element.data("DateTimePicker");
            DateTimePicker.setValueAngular = function (newValue) {
                this.angularSetValue = true; // a lock object to prevent calling change trigger of input to fix the re-cursive call of changing values
                this.setDate(newValue);
                this.angularSetValue = false;
            }

            if (!ngModel) { return; }//below this we interact with ngModel's controller

            $scope.$watch($attrs['ngModel'], function (newValue) {
                if (newValue)
                    if (newValue != "Invalid date")
                    {
                        DateTimePicker.setValueAngular(newValue);
                    }
            });

            ngModel.$formatters.push(function (value) {
                // formatting the value to be shown to the user
                var format = DateTimePicker.format;
                var date = moment(value);
                if (date.isValid()) {
                    return date.format(format);
                }
                return '';
            });

            ngModel.$parsers.push(function toModel(input) {
                // format user input to be used in code (converting to unix epoch or ...)
                var modifiedInput = moment(input).format();
                return modifiedInput;
            });

            //update ngModel when UI changes
            $element.on('dp.change', function (e) {
                if (DateTimePicker.angularSetValue === true)
                    return;

                var newValue = $element[0].value;
                if (newValue !== ngModel.$viewValue)
                    $scope.$apply(function () {
                        ngModel.$setViewValue(newValue);
                    });
                //bootstrapvalidator support
                if ($element.attr('data-bv-field') !== undefined) // if the field had validation
                    $element.closest("form").bootstrapValidator('revalidateField', $element);

            });
        });
    }
};
}); // directive end

答案 6 :(得分:0)

我也使用Angular Directive的DateTimePicker,它在这里工作正常。我用这种方式试了一下:

element.datetimepicker({
                        timepicker:false,
                        format:'Y-m-d', 
                        formatDate:'Y-m-d',
                        closeOnDateSelect: true,
                        onChangeDateTime: function(dp, $input){
                            var val = $input['context']['value'];  
                            ctrl.$setViewValue(val); 
                            ctrl.$render();  
                            scope.$apply(); 
                        } 
    //                  minDate:'-1970/01/02', // yesterday is minimum date
                        //maxDate:'+1970/01/02' // and tommorow is maximum date calendar
                    });