AngularJS 1.3: Getting to Know Async Validators
What are $asyncValidators?
The $asyncValidators, as the name suggests, are asynchronous validators — they are not executed by Angular independently. They are one of the components of the NgModelController, which is the controller for the most widely used directive in the AngularJS world: ngModel.
Where should I use an async validator?
You should use async validators together with ngModel (obviously), on a text field where a username, an email address, etc. needs to be entered.
How does it work?
Inside each validator, there must be a promise that should return either a resolve or a reject. If it returns resolved, the field will be marked as valid; if it returns rejected, the field will be marked as invalid.
When the validator is marked as invalid, a new class will be added called ng-(denormalized-name-of-your-validator)-invalid, or with the suffix -valid if it’s marked as valid.
While your form has any pending validator, the corresponding FormController will receive the $pending key, as will the corresponding field within the FormController (e.g., form.email.$pending or form.$pending).
The field will only be marked as valid or invalid once all async validators have been resolved. Until then, the $pending key will continue to exist on both the field and the form.
You can also check if your field is valid or invalid through a key inside the $error object, found within the current FormController. Example:
<form name="myForm">
<div ng-show="myForm.$pending">
Checking...
</div>
<input ng-model="user.email" unique-email>
<div ng-show="myForm.email.$pending.uniqueEmail">
Checking...
</div>
<div ng-show="myForm.email.$error.uniqueEmail">
This email is already being used by someone else.
</div>
</form>
This way, you can implement multiple async validators within a single NgModelController. See the next section to understand this better.
How to use it?
You need to learn how to use the require option of $compile, which will import the NgModelController from the current directive so you can add your async validator. Your validator will be defined by a new key in NgModelController.$asyncValidators — the key should be your validator’s name.
Example
.directive('uniqueUsername', function ($http, $q) {
return {
require: '?ngModel',
link: function (scope, element, attrs, ngModel) {
ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
var value = modelValue || viewValue;
// Look up a user by username
return $http.get('/api/users/' + value).then(function resolved() {
return $q.reject('exists');
}, function rejected() {
return true;
});
};
}
};
});
I hope you enjoyed it. Any questions, leave your comments!