I have an async validator:
app.directive('validateBar', ['$http', function($http) {
function link($scope, $element, $attrs, ngModel) {
ngModel.$asyncValidators.myValidator = function(value) {
return $http.get('/endpoint/' + value);
};
}
return {
require: 'ngModel',
link: link
};
}]);
Form template:
<form name="myForm" ng-submit="foo.$valid && saveForm()">
<input name="bar" ng-model="bar" data-validate-bar>
<p ng-show="myForm.bar.$error.myValidator">Your bar is wrong</p>
<button disabled="myForm.$invalid">
</form>
Problem: I want my accompanying form to be invalid while the myValidator
promise is pending.
I know two ways to invalidate a form while async validators are pending, but they're both verbose and/or hacky.
// Workaround 1: Mark another validator as invalid while the validator promise is pending.
// I cannot mark 'myValidator' as invalid, gets set to valid immediately by Angular.
app.directive('validateSomething', ['$http', function($http) {
function link($scope, $element, $attrs, ngModel) {
ngModel.$setValidity('async', false);
ngModel.$asyncValidators.myValidator = function(value) {
return $http.get('/endpoint/' + value).then(function() {
ngModel.$setValidity('async', true);
});
};
}
return {
require: 'ngModel',
link: link
};
}]);
<!-- Workaround 2: Prevent submitting through the UI -->
<form name="myForm" ng-submit="myForm.$valid && !myForm.$pending && saveForm()">
<input name="bar" ng-model="bar" data-validate-bar>
<p ng-show="myForm.bar.$error.myValidator">Your bar is wrong</p>
<button disabled="myForm.$invalid || myForm.$pending">
</form>
I don't like workaround 1 because I mark another validator (async
) as invalid, which may have unintended side effects, and I don't like workaround 2 because I can no longer trust form.$valid
by itself.
Does anyone know a clean solution?
AsyncFlag = invalid
. If none, and you only want it for submit allowance, then you can simply disable the submit button while your async validator promise is being resolved. – StonehamWhen the asynchronous validators are triggered, each of the validators will run in parallel and the model value will only be updated once all validators have been fulfilled. As long as an asynchronous validator is unfulfilled, its key will be added to the controllers $pending property. Also, all asynchronous validators will only run once all synchronous validators have passed.
So I guess the "right way" to do it would be by depending on the $pending property. Haven't tried it in code yet. – Djokjakarta