AngularJS - 绑定'点击'指令

时间:2014-05-31 17:48:05

标签: angularjs angularjs-directive angularjs-ng-click

我目前正在开发一个简单的模块,以屏幕右下角出现的祝酒词或弹出窗口的形式向用户显示通知。以下指令很有效,除了我更喜欢

a)使用.bind代替ng-click来处理手动驳回通知;

b)使用replace: true帮助减少一些生成的标记

toast.directive('toast', function() {
    return {
        link: function($scope, $element, $attrs, $location) {
            $scope.delayDismiss = function(index) {
                setTimeout(function() {
                    $scope.dismiss(index);
                    $scope.$apply();
                }, 5000);
            }

            $scope.dismiss = function(index) {
                $scope.messages[index].dismissed = true;
            }

            $element.bind('click', function() {
                console.log('This never triggers');
            });
        },
        replace: true,
        restrict: 'E',
        template: '<li ng-repeat="toast in messages" ng-click="dismiss($index)" ng-init="delayDismiss($index)" ng-if="!toast.dismissed">{{toast.sender}} says {{toast.message}}</li>'
    }
});

问题是,现在,$element函数中的link()引用生成的Angular注释而不是<li>,导致绑定的click事件永远不会触发。这对我没有任何意义。

我是否误解了整个指令?

1 个答案:

答案 0 :(得分:2)

  

a)使用.bind而不是ng-click处理手动解除通知;

从指令的模板中删除ngRepeat,您应该可以在指令的link函数中执行此操作。但是,我建议不要这样做,如果这只是您的偏好问题。

有关原因的详细信息,请参阅How do I “think in AngularJS” if I have a jQuery background?的答案。

您对ngRepeat的使用导致链接元素引用生成的评论节点而不是<li>

ngRepeat指令移到指令模板之外,行为更接近您的期望:

<toast ng-repeat="toast in messages"></toast>
  

b)使用replace:true help减少一些生成的标记

这很好,但请注意角度1.3文档提到replace has been deprecated并将从下一个主要版本中删除。


为了使指令更加可重复使用&#34;,我会将个人toast的逻辑移到自己的工厂,而不是试图在link函数上处理它指令。

我还会在模板<li>transclude: true中为指令的定义添加ngTransclude

查看

<ol>
  <toast ng-repeat="toast in messages">
    {{toast.sender}} says {{toast.message}}
  </toast>
</ol>

<强>控制器

controller("MainCtrl", function ($scope, $toast) {      
  $scope.addToast = function(message, sender, timeout) {
    $toast.add(message, sender, parseInt(timeout));
  };
})

<强>指令

directive('toast', function() {
  return {
    replace: true,
    restrict: 'E',
    template: '<li ng-click="toast.dismiss()" ng-transclude></li>',
    transclude: true
  }
})

<强>工厂

factory("$toast", function($rootScope, $timeout) {
  var messages = $rootScope.messages = [];
  var $toast = (function() {
    function $toast(message, sender, timeout) {
      var self = this;
      this.message = message;
      this.sender = sender;
      this.timeout = timeout || $toast.defaultTimeout;
      this.timer = $timeout(function() {
        self.dismiss();
      }, this.timeout);
    }
    $toast.prototype.dismiss = function() {
      if (this.timer) {
        $timeout.cancel(this.timer);
        this.timer = null;
      }
      var index = messages.indexOf(this);
      if (index !== -1) {
        messages.splice(index, 1);
      }
    };
    return $toast;
  })();
  $toast.defaultTimeout = 5000;
  $toast.add = function(message, sender, timeout) {
    messages.push(new $toast(message, sender, timeout));
    return $toast;
  };
  return $toast;
})

以下是一个工作示例:http://plnkr.co/edit/52JiHWi2jgloIyDst74I?p=preview