Jannik Jochem Jannik Jochem - 2 months ago 19
AngularJS Question

How can I return error context information from an AngularJS async validator?

I'm using the new AngularJS async validators feature introduced in 1.3. I have a directive that looks like this:

angular.module('app')
.directive('usernameValidator', function(API_ENDPOINT, $http, $q, _) {
return {
require: 'ngModel',
link: function($scope, element, attrs, ngModel) {
ngModel.$asyncValidators.username = function(username) {
return $http.get(API_ENDPOINT.user, {userName: username})
.then(function(response) {
var username = response.data;
if (_.isEmpty(username)) {
return true;
} else {
return $q.reject(username.error);
}
}, function() {
return $q.reject();
});
};
}
};
});


I'd like to somehow get the value of
username.error
into the model controller scope so I can display it to the user. Displaying a static message is easy, however I want to display some of the error context information returned by the server as well.

Is there a clean way to do this or am I stuck with setting properties on the model controller?

Edit: To clarify, I am not looking for a one-off solution that just works. I intend to use this directive as a reusable, cleanly encapsulated component. This means directly writing to the surrounding scope or anything like that is probably not acceptable.

Answer

the validation directive is just like any other directive, you have access to $scope, so why not set the value as it: $scope.errors.username = username.error;

angular.module('app')
    .directive('usernameValidator', function(API_ENDPOINT, $http, $q, _) {
        return {
            require: 'ngModel',
            link: function($scope, element, attrs, ngModel) {

                $scope.errors = $scope.errors | {}; //initialize it

                ngModel.$asyncValidators.username = function(username) {
                    return $http.get(API_ENDPOINT.user, {userName: username})
                        .then(function(response) {
                            var username = response.data;
                            if (_.isEmpty(username)) {
                                return true;
                            } else {
                                $scope.errors.username = username.error; //set it here
                                return $q.reject(username.error);
                            }
                        }, function() {
                            return $q.reject();
                        });
                };
            }
        };
    });

I just initialized it separately $scope.errors = $scope.errors | {}; //initialize it so that you can reuse $scope.errors object in multiple directives if you wish it

Comments