Note: I am using AngularJS 1.2
I have a form where each field will hit the server for validation on value changed.
The html snippet below (Assume for all purposes the html is set up correctly):
<div class="col-sm-5">
<input class="form-control input-sm" url="type:googleplus" ng-model="element.googleplus" type="text"><br />
<input class="form-control input-sm" url="type:yelp" ng-model="element.yelp" type="text"><br />
<input class="form-control input-sm" url="type:foursquare" ng-model="element.foursquare" type="text>
</div>
In my javascript I've set up a directive that hooks into each field and attempts to hit the server as the value updates. The scenario that breaks the current functionality is when the form is loaded with populated values.
OnValueChanged calls Validate.Options multiple times with no pause in between. I expected the server to be hit for each Validation.Options call, but instead only the last call is executed.
AngularJS below:
...
.factory('Validation', ['va', function (va) { // 'va' is a throttled resource
var result = va('/manage/api/validate?type=:type&input=:url',
{
type: '@type',
url: '@url'
},
{
options: {
method: 'options',
debounceMS: 0, // turned off debounce in lieu of this problem
abortPending: false
}
});
return result;
}])
...
.directive('url', ['$filter', 'Validation', '$q', function ($filter, Validation, $q) {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
// parses some stuff
var config = {};
(attrs['url'] || '').split(' ').map(function (p) { var a = p.split(':'); config[a[0]] = a[1]; });
if (config.type)
config.type = config.type.split(',');
config.isRequired = elm[0].required;
function validateUrl(viewValue, type) {
var deferred = $q.defer();
Validation.options({ url: viewValue, type: type }, function (response) {
deferred.resolve(response.IsValid);
});
return deferred.promise;
}
function onValueChanged(viewValue) {
// hits the server to check if the url is valid
if (viewValue) {
var type = config.type ? config.type[0] : undefined;
validateUrl(viewValue, type).then(function (isValid) {
ctrl.$setValidity('url', isValid);
});
}
else {
// prevents saving the listing as field is invalid
ctrl.$setValidity('url', !config.isRequired);
}
return viewValue;
}
ctrl.$parsers.push(onValueChanged);
// revalidate when the model updates
scope.$watch(
function () { return ctrl.$viewValue; },
function (viewValue) { return onValueChanged(viewValue); }
);
}
};
}])
Why would only the last call be executed? Popping open the network tab, I see exactly one server call with the type "foursquare".