3

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".

1 Answer 1

1

Figured it out! Had to do with the throttled resource...apparently setting the debounceMS to 0 wasn't enough to prevent it from executing the debouncing portion. I switched back to $resource and everything worked (but that also means the deboucing portion for the onValueChanged won't work).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.