【问题标题】:Add DOM event to Angular directive将 DOM 事件添加到 Angular 指令
【发布时间】:2014-11-03 15:53:28
【问题描述】:

我想将 DOM 事件附加到指令元素以更新范围属性。不幸的是,我找不到一种“干净”的方法来做到这一点。我现在可以让它工作的唯一方法是在处理程序中显式调用$apply()。这是不好的做法,我知道,但它也阻止我与本机角度指令共享此代码,例如 ng-click="myDOMEventHandler()"(因为它会触发 $apply already in progress 异常。

有没有办法将 DOM 事件添加到指令元素,以便拾取对范围的更改,而无需调用 $apply()

这是我的意思的一个简单示例。 You can edit this Plunker as well)。

angular.module('myApp', [])
.directive('myDirective', function ($compile) {
  return {
    link: function (scope, element) {
      scope.keystrokes = 0;

      var report = angular.element('<div ng-click="increment()">keystrokes: {{keystrokes}}</div>');
      element.after(report);
      $compile(report)(scope);

      scope.increment = function () {
        scope.keystrokes += 1;
        scope.$apply();
      };

      element.on('keyup', scope.increment);
    }
  };
});

如果您在输入中输入一些文本,计数器会增加。如果你点击按钮,计数器也会增加——但如果会引发$apply already in progress 异常。

如果您删除了scope.$apply(),那么异常就会消失并且范围属性会发生变化,但这些变化永远不会显示出来。

【问题讨论】:

    标签: javascript angularjs dom-events


    【解决方案1】:

    你不必在 scope.increment 函数中使用 scope.$apply 但你应该使用

    $applyelement.on('keyup'...)) 内,因为您在角度范围之外绑定了事件

    angular.module('myApp', [])
    .directive('myDirective', function ($compile) {
      return {
        link: function (scope, element) {
          scope.keystrokes = 0;
    
          var report = angular.element('<div>keystrokes and clicks: {{keystrokes}} <button ng-click="increment()">Or click me</button></div>');
          element.after(report);
          $compile(report)(scope);
    
          scope.increment = function () {
            scope.keystrokes += 1;
          
          };
          
          element.on('keyup', function(){
            
            scope.$apply(function(){
              
              scope.increment();
              
            });
            
            
          });
        }
      };
    });
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    
    <body ng-app="myApp">
      <input my-directive="" />
    </body>

    【讨论】:

    • 但是有没有办法在不将标记放入父文档的情况下做到这一点?直接将其添加到&lt;input&gt; 使其看起来像一个外部依赖项。我只是觉得指令本身应该能够处理这个问题。
    • @Andrew 在这种情况下,您可以将 scope.$apply scope.increment 移动到 element.on('keyup', ... 因为该事件在角度范围之外触发​​,您只能在此处使用 $apply执行范围生命周期
    • 感谢您的帮助。这似乎是唯一的出路。不过,真麻烦。我认为您还需要运行scope.$on('$destroy') 以干净地删除事件侦听器并且没有任何泄漏。我认为这意味着你不能在匿名函数中运行scope.$apply(),而是需要一个中间函数,1)你将keyup绑定到,2)你可以将scope.$on('$destroy')绑定到,3)运行scope.$apply()。 Angular 似乎确实应该在本地集成一些东西,因为他们已经在自己的本地指令中完成了所有这些工作。但这确实有效!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    相关资源
    最近更新 更多