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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22728585/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 20:23:51  来源:igfitidea点击:

How to wrap the datetimepicker js into AngularJS directive

javascriptangularjstwitter-bootstrap

提问by Hantsy

I have spent sometime on researching the existing datetime directives of angularjs.

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

Both ngularUI and AngularStrap do not provide a datetimepicker as I needed. Of course, I know use a datepicker and timepicker together to archive the purpose.

ngularUI 和 AngularStrap 都没有提供我需要的日期时间选择器。当然,我知道一起使用 datepicker 和 timepicker 来存档目的。

I have searched the related topic from internet and stackoverflow. Found some interesting and helpful info.

我已经从 Internet 和 stackoverflow 搜索了相关主题。发现了一些有趣且有用的信息。

http://dalelotts.github.io/angular-bootstrap-datetimepicker/, there is a datetimepicker, but I dislike the usage of this directive.

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

connecting datetimepicker to angularjs, this topic is very helpful, I tried to wrap my datetimepicker directive following the steps.

将 datetimepicker 连接到 angularjs,这个主题非常有帮助,我尝试按照步骤包装我的 datetimepicker 指令。

My work is based on https://github.com/Eonasdan/bootstrap-datetimepicker, a bootstrap 3 based datetimepicker, the UI is very nice.

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

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);
                });
            });
        }
    };
});

And use it in my view.

并在我看来使用它。

<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>

There are some problems I found.

我发现了一些问题。

  1. If the date is set via json before rendered in view, the initial date did not display, I can not see any log of the execution of ngModel render method.
  2. When I picked a date, it got a string based datetime to the json data, not a long format. And in other related fragment in the view, the string based date can not parsed by angular date filter.
  3. When used it in modal dialog, it's value is not cleared when the modal window is popup in the next time.
  1. 如果在视图中渲染之前通过 json 设置日期,则不会显示初始日期,我看不到任何 ngModel 渲染方法的执行日志。
  2. 当我选择一个日期时,它得到了一个基于字符串的 json 数据的日期时间,而不是一个长格式。在视图中的其他相关片段中,角度日期过滤器无法解析基于字符串的日期。
  3. 在模态对话框中使用时,下次弹出模态窗口时不清除该值。

Thanks in advance.

提前致谢。

回答by cdmckay

I had the same issue. Here's what I ended up doing that worked well for me:

我遇到过同样的问题。这是我最终做的对我很有效的事情:

'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());
                    });
                });
            }
        };
    });

Here's the HTML:

这是 HTML:

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

You can check out the gists and a bit more information in my blog post.

您可以查看我的博客文章中的要点和更多信息。

回答by Atais

I really struggled long with Eonasdan datetime picker. Most of the solutions published on the web work ok or not-so ok.

我真的在Eonasdan 日期时间选择器上挣扎了很长时间。网络上发布的大多数解决方案都可以正常工作或不太正常。

In the end I merged some of the solutions I have found online. I wrapped it in a working plunker: http://plnkr.co/n8L8UZ

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

The directive works using ng-modelin momentformat, what is more it allows two functions to be passed: onDateChangeFunctionand onDateClickFunctionwhich are called respectively.

使用该指令的作品ng-modelmoment形式,更重要的是它可以让两个函数传递: onDateChangeFunctiononDateClickFunction其分别调用。

Happy using!

使用愉快!



The directive source code:

指令源代码:

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));
          }
        };
      }
    ]);

回答by Atais

Can help you with the first point; add $watchto your element inside the link function and set

可以帮助你解决第一点;将$watch添加到链接函数内的元素并设置

 value="{{$scope.variableWithTheInitialDate}}" 
在文本字段中;这样加载时,日期时间选择器将已经设置。


对于第二点,我会使用moment.jsmoment.js但还没有尝试过你的例子来告诉你如何 :-P 祝你好运!

回答by Richard

A possible solution to problem 1:

问题 1 的可能解决方案:

You will need to set the view value to the date that is in the model right from the beginning, by doing something like this:

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

if (ngModel.$viewValue) {

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

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

    ....

  });

}

回答by Siggen

To complete cdmckay's solutionso the datetime picker widget is correctly initialized with the ng-model's value, I've added a listener on dp.showevent. So, my solution is :

为了完成cdmckay 的解决方案,以便使用 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);
                  });
              });
          }
      };
  });

回答by mohghaderi

I ended up putting the input inside of a div and bind model to that. It also includes bootstrapvalidator (Sorry, I didn't have time to make the code perfect, but you should get the idea)

我最终将输入放在一个 div 中并将模型绑定到它。它还包括 bootstrapvalidator(抱歉,我没有时间使代码完美,但您应该明白了)

Sample html code:

示例 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>

And javascript code:

和 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

回答by Muhammad Mehdi Raza

I am also using DateTimePicker by Angular Directive and it is working fine here. I tried it in this way:

我也在使用 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
                    });