Decorating the ng-click directive in AngularJs
Asked Answered
S

2

16

I've been looking into modifying the AngularJS ng-click directive to add some additional features. I have a few different ideas of what to use it for, but a simple one is to add Google Analytics tracking to all ng-clicks, another is to prevent double clicking.

To do this my first thought was to use a decorator. So something like this:

app.config(['$provide', function($provide) {
  $provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
    // Trigger Google Analytics tracking here
    return $delegate;
  }]);
}]);

But this won't work as decorators are fired on instantiation, not when the expression in the directive is met. So in this case it would do the analytics when an element with the directive loads, not when the element is clicked.

So on to the real question. Is there some way for a decorator to get at the element that the directive is instantiated on? If I could, from the delegate, get to the element I could bind my own click event on it to trigger in addition to the ng-click.

If not, how would you go about adding something on all ng-clicks?

Stomatitis answered 20/8, 2013 at 12:51 Comment(0)
B
19

You can certainly use a decorator to add functionnality. I've made a quick plunkr to demonstrate how. Basicaly, in your decorator body, you replace the compile function with your own for your custom logic (in the example, binding to the click event if the track attribute is present) and then call the original compile function. Here's the snippet:

$provide.decorator('ngClickDirective', function($delegate) {
  var original = $delegate[0].compile;
  $delegate[0].compile = function(element, attrs, transclude) {
    if(attrs.track !== undefined) {
      element.bind('click', function() {
        console.log('Tracking this');
      });
    }
    return original(element, attrs, transclude);
  };
  return $delegate;
})
Bunn answered 20/8, 2013 at 13:31 Comment(4)
Ahh, of course. I was too focused on finding the element instead of just making a new function :P Thanks!Stomatitis
@ErikHonn No problem. I've never had to use a decorator and this was certainly a fun exercise for me. :)Bunn
I don't think this works anymore because when I try to access the new scope property in code it is not availble. Here is the fiddle jsfiddle.net/377vhfm4/3Cytoplast
Sorry this does not work in angular 1.3.* latest versionCytoplast
K
7

This is the correct updated version (improved from the answer):

$provide.decorator('ngClickDirective', function($delegate) {
    var compile = $delegate[0].compile;
    $delegate[0].compile = function() {
       var link = compile.apply(this, arguments);
       return function(scope, element, attrs, transclude) {
           if (attrs.track !== undefined) {
               element.bind('click', function() {
                   console.log('Tracking this');
               });
           }
           return link.apply(this, arguments);
       };
    };
    return $delegate;
});
Kagoshima answered 5/12, 2015 at 15:24 Comment(1)
This (unlike the accepted answer) works for Angular 1.3.Macmillan

© 2022 - 2024 — McMap. All rights reserved.