When the Angular Directive Name Really Matters

I just met strange behavior from Angular:

Here's the script:

In the registration form, I want to check the uniqueness of email (via an HTTP call to the server).
So I created a directive called emailUnique , whose client code is:

 <form name="form" novalidate> <!-- some other fields --> <input name="email" type="email" ng-model="user.email" required email-unique/> </form> 

For the rest of the message, suppose the user types: michael , i.e., obviously invalid mail.

Let's look at the interesting part of my directory code, invoking the behavior that interests me:

 angular.module('directives.emailUnique', []) .directive('emailUnique', function () { return { restrict: 'A', require: 'ngModel', link: function (scope, el, attrs, ctrl) { ctrl.$parsers.push(function (viewValue) { console.log(viewValue); //What do you expect here for viewValue? answer below }); } }; }); 

Before giving an answer, at first glance, it will logically respond:

 undefined 

Why? Because:

  • The exact attribute is type="email" , not just type="text"
  • michael not a valid mail.
  • Angular The compiler is supposed to conform to the classic HTML behavior.

After testing, the answer will be undefined , as expected. My complete directory logic will be based on this, and everything works fine.

Now rename the directive: emailUnique becomes somethingUnique .
Customer now:

 <input name="email" type="email" ng-model="user.email" required something-unique/> 

Surprise: console.log(viewValue) : michael now displayed, not undefined ...

It is clear that starting with email for a name has a strange effect when working with the email field in this case.

My question is simple: Is there a good reason? A possible mistake? Perhaps I misunderstood some concept?

Some additional notes:

  • The Angular email field documentation with angular does not specify the email attribute, which may interfere with email-unique . Indeed, it is based on type="email"
  • I ran into the same problem whether the novalidate form attribute is novalidate or not.
+6
source share
1 answer

The problem is the priority of the directive. Since you are dependent on the time when your parsers are added, you want to set the priority of the directive, which will provide the necessary time.

In your demo, the somethingUnique directive is run before validation is added to the list of parsers (it ends in the middle of 3 parsers). While with emailUnique it is added after.

Setting the priority of your directive to something greater than 0 ensures that it fires after emailValidation, always giving you undefined (noting from $ compile docs : "post-link functions are executed in the reverse order"). To confirm this, you can force emailUnique be emailUnique by setting the priority to something less than 0.

So this fixes the problem:

 .directive('somethingUnique', function () { return { restrict: 'A', require: 'ngModel', priority: 100, link: function (scope, el, attrs, ctrl) { ctrl.$parsers.push(function (viewValue) { console.log(viewValue); }); } }; }); 

Updated plunker

Update problem with name: Angular seems to process directives with the same priority in alphabetical order. Thus, homethingUnique acts like emailUnique , since both come before input , and jomehtingUnique behaves like somethingUnique - it works after input.

But Angular docs say: "The order of directives with the same priority is undefined." Therefore, we cannot count on an alphabetical sequence.

+5
source

All Articles