Angular JS

Una de las directivas más potentes, imprescindibles y más utilizadas de angular es ng-model. Aunque la mayor parte del tiempo trabajemos en el caso básico de editar un valor del scope, esta directiva nos ofece un gran abanico de opciones para ampliarla utilizando el controlador que la gobierna, ngModelController.

Aprovechando el ngModelController podemos crear directivas que complementen y amplien la funcionalidad de ngModel por composición. Al fijar el atributo "require: 'ngModel'" de la directiva, además de obligar a que se use en un elemento con ngModel, tenemos la opción de recibir el ngModelController en el cuarto parámetro del link o el post-compile. Las aplicaciones son varias: crear inputs customizados, formatear el valor del ngModel, validarlo, etc. Dentro de estas aplicaciones, nos centraremos en el caso de la validación asíncrona de valores, por ejemplo, para realizar una validación en el servidor.

Empezaremos creando una directiva que requiera ngModel y lo reciba como cuarto parámetro en la función de link. Con el ngModelController recibido, solo tenemos que añadir una función a su atributo $asyncValidators que contiene un objeto con todos los validadores que se aplicarán al valor del ng-model. Utilizaremos un nombre que sea representativo de nuestro validador para evitar sobrescribir alguno de los ya presentes añadidos por otras directivas.

Las funciones que añadimos al objeto $asyncValidators como propiedades deben cumplir las siguientes condiciones:

  • Deben devolver un promise.
  • En caso de que el promise se resuelva, el input se condirerá válido.
  • De forma alternativa, en caso de que el promise se rechace, se considerará inválido.

Documentación detallada aquí

Nuestro ejemplo se utilizará únicamente una directiva de atributo para validar el valor contenido en un input. Como hemos comentado, la directiva hará un require del ngModel y utilizará su controlador en el link para añadir un asyncValidator. Dentro de la función, devolveremos una promise, haremos una petición utilizando el servicio $http y en función del resultado resolveremos la promise devuelta.

MyModule.directive('myAsincValidator', function ($http, $q) {
    return {
        restrict: 'A',
        scope: {
        },
        require: 'ngModel',
        link: function (scope, element, attrs, ngModelCtrl) {
            ngModelCtrl.$asyncValidators.asincValidator = function (value) {
                var deferred = $q.defer();
                $http.post('/validate/', {value: value}, function (result) {
                    if (result.is_valid === false) {
                        deferred.reject("The email is not valid for the promo code");
                    }
                    deferred.resolve(true);
                });
                return deferred.promise;
            };
        }
    };
});

En definitiva, hemos creado un validador asíncrono que puede funcionar con cualquier tipo de input y que se integra dentro de la funcionalidad estándar del ngModel. Eso significa que nuestro validador funcionará correctamente con cualquier otra parte de Angular, aunque en este caso, destacaremos que el sistema de formularios de Angular recibirá los errores de validación.

blog comments powered by Disqus