javascript - 如何为 ui-bootstrap 日期选择器创建一个 angularJs 包装器指令?

标签 javascript jquery angularjs angularjs-directive angular-ui-bootstrap

我正在使用 ui.bootstrap.datepicker显示一些日期字段的指令。但是大多数时候我需要相同的设置:我希望它带有一个弹出窗口和一个弹出按钮,我还想要文本的德语名称。这确实会一遍又一遍地为按钮、文本和格式创建相同的代码,因此我编写了自己的指令以防止自己重复。

Here is a plunkr按照我的指示。但是我似乎做错了。如果您使用不使用我的指令的“日期 1”日期选择器选择日期选择器,则一切正常。 我希望 Date 2 也一样,但不是根据我在输入字段中提供的模板(或我期望的任何其他值)显示日期,而是显示 .toString() 表示日期对象(例如 Fri Apr 03 2015 00:00:00 GMT+0200 (CEST))。

这是我的指令:

angular.module('ui.bootstrap.demo').directive('myDatepicker', function($compile) {
  var controllerName = 'dateEditCtrl';
  return {
      restrict: 'A',
      require: '?ngModel',
      scope: true,
      link: function(scope, element) {
          var wrapper = angular.element(
              '<div class="input-group">' +
                '<span class="input-group-btn">' +
                  '<button type="button" class="btn btn-default" ng-click="' + controllerName + '.openPopup($event)"><i class="glyphicon glyphicon-calendar"></i></button>' +
                '</span>' +
              '</div>');

          function setAttributeIfNotExists(name, value) {
              var oldValue = element.attr(name);
              if (!angular.isDefined(oldValue) || oldValue === false) {
                  element.attr(name, value);
              }
          }
          setAttributeIfNotExists('type', 'text');
          setAttributeIfNotExists('is-open', controllerName + '.popupOpen');
          setAttributeIfNotExists('datepicker-popup', 'dd.MM.yyyy');
          setAttributeIfNotExists('close-text', 'Schließen');
          setAttributeIfNotExists('clear-text', 'Löschen');
          setAttributeIfNotExists('current-text', 'Heute');
          element.addClass('form-control');
          element.removeAttr('my-datepicker');

          element.after(wrapper);
          wrapper.prepend(element);
          $compile(wrapper)(scope);

          scope.$on('$destroy', function () {
              wrapper.after(element);
              wrapper.remove();
          });
      },
      controller: function() {
          this.popupOpen = false;
          this.openPopup = function($event) {
              $event.preventDefault();
              $event.stopPropagation();
              this.popupOpen = true;
          };
      },
      controllerAs: controllerName
  };
});

这就是我使用它的方式:

<input my-datepicker="" type="text" ng-model="container.two" id="myDP" />

(概念灵感来自 this answer )

我正在使用 angular 1.3(plunker 在 1.2 上,因为我刚刚从 angular-ui-bootstrap datepicker 文档中 fork 了 plunker)。我希望这不会造成任何影响。

为什么我输入的文本输出错误,如何正确完成?

更新

与此同时,我取得了一点进步。在阅读了更多有关编译和链接的详细信息后,在 this plunkr我使用编译函数而不是链接函数来进行 DOM 操作。我仍然对文档中的这段摘录感到有些困惑:

Note: The template instance and the link instance may be different objects if the template has been cloned. For this reason it is not safe to do anything other than DOM transformations that apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration should be done in a linking function rather than in a compile function.

特别是我想知道“适用于所有克隆的 DOM 节点”是什么意思。我最初认为这意味着“适用于 DOM 模板的所有克隆”,但事实并非如此。

无论如何:我的新编译版本在 chromium 中运行良好。在 Firefox 中,我需要先使用日期选择器选择一个日期,然后一切正常(如果我在日期选择器的日期解析器中将 undefined 更改为 null ( plunkr ),Firefox 的问题就会自行解决)。所以这也不是最新的事情。此外,我使用 ng-model2 而不是我在编译期间重命名的 ng-model 。如果我不这样做,一切都还是坏的。仍然不知道为什么。

最佳答案

老实说,我不太确定为什么会这样,以及是什么导致您的日期在输入中显示之前被“toString-ed”。

但是,我确实找到了重组指令的地方,并删除了很多不必要的代码,例如指令中的 $compile 服务、属性更改、范围继承、require等等。我使用了独立作用域,因为我不认为每个指令的使用都应该知道父作用域,因为这可能会导致 future 的恶性错误。这是我更改的指令:

angular.module('ui.bootstrap.demo').directive('myDatepicker', function() {
  return {
      restrict: 'A',
      scope: {
          model: "=",
          format: "@",
          options: "=datepickerOptions",
          myid: "@"
      },
      templateUrl: 'datepicker-template.html',
      link: function(scope, element) {
          scope.popupOpen = false;
          scope.openPopup = function($event) {
              $event.preventDefault();
              $event.stopPropagation();
              scope.popupOpen = true;
          };

          scope.open = function($event) {
            $event.preventDefault();
            $event.stopPropagation();
            scope.opened = true;
          };

      }
  };
});

您的 HTML 用法变为:

<div my-datepicker model="container.two" 
                   datepicker-options="dateOptions" 
                   format="{{format}}"  
                   myid="myDP">
</div>

编辑:将id 添加为指令的参数。 Plunker 已更新。

Plunker

关于javascript - 如何为 ui-bootstrap 日期选择器创建一个 angularJs 包装器指令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29562213/

相关文章:

javascript - jQuery 使用自定义顺序对 HTML 表格进行排序

javascript - 错误 TS2349 : Cannot invoke an expression whose type lacks a call signature. 类型 '{ ; }' 没有兼容的调用签名

javascript - AngularJs:无法切换两个元素的可见性

javascript - 我的 ajax 请求提交一次,然后提交两次,然后提交 4 次并不断加倍

php - 如何在 CakePHP Controller 中获取格式化的 JSON 输出

javascript:如何阻止页面重新加载?

javascript - 传单javascript - 如何清除标记上的setTimeout?

javascript - html 源代码中看不到脚本标签

javascript - Crontab 未运行重新加载页面的 javascript

javascript - Angular X 可编辑只有一行应该被编辑,如果我单击下一行编辑上一行应该重置为初始状态