Reputation: 1684
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:
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:
$asyncValidators.usernameAvailable
to be resolved or rejectedI 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;
}
}
};
}]);
Upvotes: 2
Views: 1383
Reputation: 8055
The simplest way would be to just disable the user input like:
<input
name="username"
ng-model="user.username"
ng-model-options="{ updateOn: 'blur' }"
ng-disabled="myForm.$pending"
check-availability />
So once the user tabs out of the username field, the validation is triggered and the field is disabled (you could also disable to submit button).
If that's not an acceptable UX, you could instead use the method described here : http://www.bennadel.com/blog/2616-aborting-ajax-requests-using-http-and-angularjs.htm
Essentially $http
allows for a promise to be set on its timeout
property. If you then resolve
that property, the http call is aborted. It might take some trial and error to figure out the best approach within the validator.
Upvotes: 1