I've just read the awesome angular page on form validation and I've probably missed something but how can I apply ng-model-options
debounce
property on a specific validator.
Let me explain the problem. I have a form that validate a public key and for that I have a directive called key-check that contains multiple validator. Some of them are local and synchronous like the format of the key and there is another asynchronous that check if the key is available on the server (asynchronously).
I don't want my server to be flood nor the angular application to be slowed so I use that the cool kids call debouncing and my input seems something like :
<input type="text" ... ng-model="key" key-check ng-model-options="{ debounce: 700 }" ng-minlength="5" ng-maxlength="50"/>
And the directive is like :
ctrl.$validators.keyFormatCheck = function(modelValue) {
// return boolean
}
ctrl.$asyncValidators.KeyAvailabilityCheck = function(modelValue) {
// return promise
}
It's work like a charm but all the check are done with 700ms latency and I wonder if it's possible to do the keyFormatCheck without debouncing and the KeyAvailabilityCheck with it. I can probably use the old good way with $timeout but I prefer to do it the angular way.
Any ideas ?
ngModelController
's debounce
applies to the entire pipeline of parsers, validators and view-change-listeners (e.g. ng-change
).
There is no way today (Angular v1.4) with ngModelOptions
to isolate the debounce
delay to a specific validator.
But the functionality is easily achieved by passing a delay parameter to your own async validator directive:
<input ng-model="val" foo-validator="{delay: 500}">
You implement the actual delay with $timeout
; no reason here to avoid using $timeout
on the grounds that it is somehow less than "the Angular way"; it's not.
The only trick is to make sure that you cancel the previous pending validation request before executing a new one.
var pendingValidation;
ngModel.$asyncValidators.foo = function(modelValue, viewValue){
if (pendingValidation) $timeout.cancel(pendingValidation);
pendingValidation = $timeout(function(){
pendingValidation = null;
// returns promise or value
return doAsyncValidation();
}, delay);
return pendingValidation;
};
delay
can be obtained from a parameter via a foo-validator
attribute, either with isolate scope binding (scope: {config: "=fooValidator"}
), or by directly using $eval
-ing the attribute expression against the right scope:
var config = $scope.$eval(attrs.fooValidator);
var delay = config.delay;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With