如何编写挂钩到ng-click处理程序的指令

时间:2013-07-12 22:22:03

标签: javascript angularjs angularjs-directive

我正面临Angular的情况,我觉得我做错了什么,但我找不到Angular方法来解决它。

我正在开发一款移动应用。我想创建一个指令,让我们称之为cc-tap-highlight,它将与ng-click结合使用。这意味着我可以像这样使用它:

<a ng-click="doSomething()" cc-tap-highlight>Click me</a>

这样做的目的是为点击的元素添加一个类,并在几秒后删除它。

现在可以说,让我们手动绑定到指令中的元素click事件。这适用于桌面应用程序。但是,在移动设备上,Angular为我们提供了快速点按/点击的神奇功能:

https://github.com/angular/angular.js/blob/master/src/ngMobile/directive/ngClick.js

当然,我不想重新实现它的所有魔力!

所以,目前,我没有使用cc-tap-highlight指令,而是采用了这种相当狡猾的方法:

在视图中

<a ng-click="doSomething($event)" cc-tap-highlight>Click me</a>

在控制器中:

$scope.doSomething = function($event){
    //do your things with $event.currentTarget
}

这种方法存在两个主要问题:

  1. 控制器不应该操纵DOM

  2. 我们需要在整个代码库中反复重复这种模式,违反DRY

  3. 但是,我不能为我的生活,弄清楚如何编写一个挂钩到ng-click处理程序的指令并做它的事情。

1 个答案:

答案 0 :(得分:2)

您可以尝试让您的指令生成带有包装函数的ng-click指令。

Here's一个简单的例子。到目前为止还没有经过彻底的测试,但我认为原则是合理的。你想要的是你的自定义代码在点击事件之前/之后运行,无论它是如何触发的(点按,点击,等等)。

这确实有一个缺点,就是它创建了一个新的范围,因此没有测试与可能需要隔离范围的其他指令的交互。

<强>指令

app.directive('myClick', ['$parse','$compile', function($parse, $compile) {
  return {
    restrict: 'A',
    compile : function(tElement, tAttrs, transclude) {
      //you can call the wrapper function whatever you want.
      //_myClick might be more appropriate to indicate it's not really public
      tElement.attr('ng-click', 'myClick($event)');
      tElement.removeAttr('my-click');
      var fn = $parse(tAttrs['myClick']);

      return {
        pre : function(scope, iElement, iAttrs, controller) {
          console.log(scope, controller);
          scope.myClick = function(event) {
            console.log('myClick.before');
            fn(scope, {$event:event});
            console.log('myClick.after');
          };

          $compile(iElement)(scope);
        },
        post : function postLink(scope, iElement, iAttrs, controller) {

        }
      };
    },
    scope : true
  };
}]);

<强> CONTROLLER

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';

  $scope.test = function($event) {
    console.log('test', $event);
  };

  //this is to show that even if you have a function with the same name,
  //the wrapper function is still the one bound thanks to the new scope
  $scope.myClick = function() {
    console.log('dummy my click');
  };
});

<强> HTML

<button ng-click="test($event)">NG-CLICK</button>
<button my-click="test($event)">MY-CLICK</button>
<button ng-click="myClick($event)">MY-CLICK-DUPLICATE-FN</button>