I have a simple HTML5 user registration form. The value of the username input is validated to ensure that there are no users with the same username using a custom function added to $asyncValidators.
Consider the following situation:
- User starts typing in a username (e.g., 'Me').
- After a slight delay, Angular validators run, sending asynchronous request to server asking if the username is available.
- User begins typing more characters (e.g., 'Me123').
- After another slight delay, Angular again tries to validate the username by sending another request to server.
What does Angular do when it receives two responses regarding the validity of the username? Is there a way to handle this gracefully?
What I'd like to do is somehow cancel or tell Angular to ignore the result of the first validation attempt as soon as the user modifies the username value.
EDIT 11/12/2015:
sirrocco's answer helped me clarify my question. There are two pieces here:
- abort actual HTTP request
- tell Angular validation process to stop waiting for the promise returned from
$asyncValidators.usernameAvailableto be resolved or rejected
I could do the first by using the timeout option of the $http service. My question is: Is it necessary, desirable, or possible to do the second? If so, how?
I'm thinking this might happen in a a keyup event handler added to the element in the directive link. See below:
index.html
<input
ng-model="user.username"
ng-model-options="{ debounce: 250 }"
check-availability />
checkAvailability.directive.js
function affectsText(keyCode) {
// some code to determine if keyCode could change value of a text input
}
angular
.module('app')
.directive('checkAvailability', ['$q', 'users', function($q, users) {
return {
restrict: 'AC',
require: 'ngModel',
link: function (scope, element, attrs, ctrl) {
element.on('keyup', function(e) {
if (!affectsText(e.keyCode)) {
return;
}
// cancel previous $asyncValidators.usernameAvailable process??
// users service cancels operation by rejecting a promise previously assigned to to $http's timeout option
users.cancelIsAvailableCheck();
});
ctrl.$asyncValidators.usernameAvailable = function(modelValue) {
if (ctrl.$isEmpty(modelValue)) {
return $q.when();
}
var deferred = $q.defer();
users.isAvailable(modelValue).then(function(available) {
if (available) {
deferred.resolve();
} else {
deferred.reject();
}
});
return deferred.promise;
}
}
};
}]);