3

I was having doubts about how to implement a custom event in Angular, so I though, "wait, why not check the Angular default events directives, like ng-click, etc"?

So I found this here.

And here are the relevant bits:

['$parse', function($parse) {
  return {
    compile: function($element, attr) {
      var fn = $parse(attr[directiveName]);
      return function(scope, element, attr) {
        element.on(lowercase(name), function(event) {
          scope.$apply(function() {
            fn(scope, {$event:event});
          });
        });
      };
    }
  };
}];

That's how each event directive is declared. Using the compile method.

But here I have my doubts. Why 2 different $element and element, in what situation those two are going to differ? Why use the compile method, if you can just use link? Why $parse if you can $eval?

I mean, I would just do something like:

function() {
  return {
    link: function(scope, element, attr) {
      element.on(lowercase(name), function(event) {
        scope.$apply(function() {
          scope.$eval(attr[directiveName], {$event: event});
        });
      };
    }
  };
};

What are the advantages/differences of the Angular approach, vs my approach?

Zequez
  • 3,399
  • 2
  • 31
  • 42
  • This provides useful information on link vs compile vs controller for angular function organization: http://stackoverflow.com/questions/24615103/angular-directives-when-and-how-to-use-compile-controller-pre-link-and-post/24615123#24615123 – Tony Brasunas Sep 22 '16 at 21:13

2 Answers2

2

Angular first compiles the markup and eventually creates a clone af the DOM-Element. This happens for example within an ng-repeat directive. After the compile phase the DOM-Elements are linked with a scope. So one should do tasks during the compile phase that are equal for all instances. In this case it is the $parse method that is equal for all instances.

The complie function returns a link function - otherwise there where no posibility using the precompiled informations. In the link function the event is bind to the DOM-Element. Remember this may be a clone of the original DOM-Element. e.g. we have $element and element. The second is eventually a clone of $element.

So your code is correct too, but the angular one consumes less ressources if there is cloning necessary. As for example with elements/directives in an ng-repeat.

michael
  • 16,221
  • 7
  • 55
  • 60
  • Small plunker that displays this behavior: http://plnkr.co/edit/Z5NDQ5e2Bga2h1XVMyB3?p=preview – null Jan 08 '14 at 15:54
1

Before angular v1.0.0rc1 this directive looked like so:

ngEventDirectives[directiveName] = valueFn(function(scope, element, attr) {
    element.bind(lowercase(name), function(event) {
      scope.$apply(attr[directiveName]);
      event.stopPropagation();
  });
});

This commit is part of angular v1.0.0rc1

feat(directive): event now accessible as $event

This commit is part of angular v1.2.0

fix(ngEventDirectives): parse expression only once during compile phase

As you can see, angular.js guys thought exactly like you do but eventually they had to make some little optimizations, it's all about efficiency.

Ilan Frumer
  • 32,059
  • 8
  • 70
  • 84