Tengo un formulario con campos de entrada y validación de la instalación mediante la adición de la required atributos y tal. Pero para algunos campos tengo que hacer una validación adicional. ¿Cómo me «toca» a la validación que FormController controles?

De validación personalizada podría ser algo así como «si estos 3 campos están llenos, a continuación, este campo es obligatorio y debe estar formateado de una manera particular».

Hay un método en FormController.$setValidity pero que no tiene el aspecto de una API pública así que prefiero no usarlo. Crear una personalizada directiva y el uso de NgModelController se ve como otra opción, pero básicamente me requieren para crear una directiva para cada regla de validación, que yo no quiero.

Realidad, marcando un campo desde el controlador no válido (manteniendo también FormController en sincronización) podría ser la cosa que necesito en el escenario más sencillo para conseguir el trabajo hecho, pero no sé cómo hacerlo.

  • Hay un buen artículo sobre la codificación monstruo para el manejo de las validaciones personalizadas en angular JS. Verificar este fuera
  • No es exactamente lo que estoy buscando, ya que requiere de directivas personalizadas, pero voy a aceptar tu respuesta, ya que es un buen artículo de todos modos.
  • Me pregunto lo mismo, me encantaría un poco de control en el nivel de la FormController. Por ejemplo, quiero determinadas directivas personalizadas para marcar la FormController instancia como algo parecido a formName.$warning.
  • Creo que $$ precede a la no-pública de la api, con $ ser de dominio público. Consulte stackoverflow.com/questions/19338493/…
InformationsquelleAutor botteaap | 2012-09-25

12 Comentarios

  1. 365

    Edit: se ha añadido información acerca de ngMessages (>= 1.3.X) a continuación.

    Forma estándar de validación de mensajes (1.0.X y superior)

    Ya que este es uno de los mejores resultados si se busca en Google «Forma Angular de Validación», en la actualidad, quiero añadir otra respuesta a esta para cualquiera que venga de allí.

    Hay un método en FormController.$setValidity pero que no tiene el aspecto de una API pública así que prefiero no usarlo.

    Es «público», no se preocupe. El uso de la misma. Eso es lo que es. Si no fuera destinado a ser usado, el Angular devs habría privatizado en un cierre.

    Para hacer de validación personalizada, si usted no desea utilizar Angular de interfaz de usuario como la otra respuesta sugerido, usted puede simplemente rodar su propia validación de la directiva.

    app.directive('blacklist', function (){ 
       return {
          require: 'ngModel',
          link: function(scope, elem, attr, ngModel) {
              var blacklist = attr.blacklist.split(',');
    
              //For DOM -> model validation
              ngModel.$parsers.unshift(function(value) {
                 var valid = blacklist.indexOf(value) === -1;
                 ngModel.$setValidity('blacklist', valid);
                 return valid ? value : undefined;
              });
    
              //For model -> DOM validation
              ngModel.$formatters.unshift(function(value) {
                 ngModel.$setValidity('blacklist', blacklist.indexOf(value) === -1);
                 return value;
              });
          }
       };
    });

    Y he aquí un ejemplo de uso:

    <form name="myForm" ng-submit="doSomething()">
       <input type="text" name="fruitName" ng-model="data.fruitName" blacklist="coconuts,bananas,pears" required/>
       <span ng-show="myForm.fruitName.$error.blacklist">
          The phrase "{{data.fruitName}}" is blacklisted</span>
       <span ng-show="myForm.fruitName.$error.required">required</span>
       <button type="submit" ng-disabled="myForm.$invalid">Submit</button>
    </form>

    Nota: en 1.2.X es probablemente la copa de sustituir ng-if para ng-show por encima de

    Aquí es obligatorio plunker enlace

    También, he escrito un par de entradas en el blog sobre este tema que va a un poco más de detalle:

    Angular De La Validación De Formularios

    Validación Personalizada Directivas

    Editar: usar ngMessages en 1.3.X

    Ahora puede utilizar el ngMessages módulo en lugar de ngShow para mostrar los mensajes de error. Realmente funcione con cualquier cosa, no tiene que ser un mensaje de error, pero aquí está lo básico:

    1. Incluyen <script src="angular-messages.js"></script>
    2. Referencia ngMessages en su declaración del módulo:

      var app = angular.module('myApp', ['ngMessages']);
    3. Añadir el marcado adecuado:

      <form name="personForm">
        <input type="email" name="email" ng-model="person.email" required/>
      
        <div ng-messages="personForm.email.$error">
          <div ng-message="required">required</div>
          <div ng-message="email">invalid email</div>
        </div>
      </form>

    En el sobre marcado, ng-message="personForm.email.$error" básicamente especifica un contexto para la ng-message niño directivas. Luego ng-message="required" y ng-message="email" especificar las propiedades en ese contexto de reloj. Lo que es más importante, también se especifica una orden de verificación en. El primero que encuentre en la lista que es «truthy» gana, y se mostrará el mensaje y ninguno de los otros.

    Y un plunker para la ngMessages ejemplo

    • Si el valor de retorno de la función que se le pasa $analizadores.unshift, valores erróneos que se guardará en el modelo también – mejor sería volver indefinido yo creo (cuando el valor no es válido).
    • +1 @georgiosd… 100% correcto. Mirando a través de lo que Angulares no, que estamos volviendo indefinido. Probablemente no es una gran acuerdo para devolver el valor, ya que (con suerte) modelos de inválido formas no presentado… pero mejor prevenir que lamentar, supongo.
    • Cosas grandes! Si usted buscado en Google el camino de aquí en busca de una buena valoración crítica de la validación personalizada en Angular, echa un vistazo a lo que @blesh escribió
    • ¿Has comprobado Avanzado validación de formularios con AngularJS y los filtros? Se resuelve el filtro de validación de forma genérica.
    • Para hacer que funcione con el nuevo ngMessages módulo de la «ngModel.$los analizadores.unshift» debe ser «valor de retorno»; o sería una muestra siempre el necesario mensaje de error en lugar de el mensaje correcto.
    • No es una mala respuesta pero, ¿cómo responder a la pregunta: «si estos 3 campos están llenos, a continuación, este campo es obligatorio y debe estar formateado de una manera particular». Necesito una validación simple, donde ya sea por correo electrónico o teléfono debe ser proporcionada. Si ambos están vacíos, entonces es «Favor de proporcionar válida de correo electrónico o teléfono» es uno de ellos está lleno, pero no válido, entonces es «Favor de proporcionar una válida de correo electrónico/teléfono». Me preguntaba cómo acceder a otras entradas/valores de validar la función como sólo se aprobó la viewValue y de control, no de la forma como un todo.
    • Si el formulario está configurado correctamente, sólo tienes que hacer esto: <span ng-show="myForm.email.$error.required && myForm.phone.$error.required">Please provide email/phone</span> y <span ng-show="(!myForm.email.$error.required && myForm.email.$error.email) || (!myForm.phone.$error.required || !myForm.phone.$error.pattern)">Please provide a valid email/phone</span>
    • Gracias por su respuesta, que no trabajo para mí, porque me obliga a definir el dominio de las reglas en la plantilla(s). Han establecido una directiva general para ser utilizado como un proxy entre la plantilla y las reglas del servicio, pero no está seguro de cómo obtener la forma: stackoverflow.com/q/25309522/1641941
    • Lo que si he personalizado la directiva elemento de formulario. No es una entrada. Algo así como <div uploader> Y quiero usar ngMessage a la pantalla de error. Sé cómo crear esos errores, pero en este. myForm.email.$error. ¿Cómo puedo construir el camino para que la directiva? lo que pongo en lugar de correo electrónico?
    • son ngMessages todavía en beta? Parece, que ahora forman parte de AngularJS 1.3.x.
    • no, ya no es beta, están en la 1.3, que ha sido lanzado.
    • «El primero que encuentre en la lista que es «truthy» gana, y se mostrará el mensaje y ninguno de los otros.» <- sería genial tener una opción para mostrar todos los mensajes en lugar de sólo el primero. Yo prefiero ver todos mis errores a la vez en lugar de golpear a Presentar y ser «acusado» para el próximo error, y luego el siguiente y así sucesivamente.
    • ¿Por qué es «la copa de sustituir ng-if para ng-show«
    • realmente, es del caso-por-caso ng-si se desmontaje/instalación de las directivas adoptadas en virtud de sí mismo, y evitar dejar las cosas cable que no es necesario ser. Pero en el más simple de los casos de uso como este, probablemente no importa mucho, y que incluso puede ser más rápido usar ng-show, porque usted no tiene que configurar enlaces y tal vez sobre lo que se muestra cuando se reveló.
    • ¿Por qué el $formaters (es decir, DOM) de la directiva de retorno false para inválidos, mientras que los $analizadores` (es decir, el modelo de la sección de devoluciones undefined? ¿Por qué no devuelven undefined?
    • podría uno a través del validador de alguna manera, que cuando algunos validador de falla, a continuación, en el mensaje conectado a este validador uso de alguna variable. Por ejemplo, si validador comprueba la longitud del texto, entonces es fácil de decir, ¿cuál es la duración esperada. Se podía hacer eso con ngMessages?
    • Sí, podría hacer que @Eugene. Sólo iba a ser complicado si la longitud deseada fue de alguna manera dinámica. Pero incluso eso sospecho que no sería tan malo.
    • Creo que puede haber significado para hacer return value ? valid : undefined arriba.
    • Puede por favor compartir la validación de un juego de casillas de verificación y no sólo una sola casilla el valor de uso de ng-mensajes ?
    • No es este un poco fuera de fecha? $validators son el método sugerido en AngularJS 1.3 y en. busypeoples.github.io/post/formas-de-angularjs

  2. 92

    Angular-interfaz de usuario del proyecto incluye una interfaz de usuario-validación de la directiva, que probablemente le ayudará con esto. Se le permite especificar una función a llamar para hacer la validación.

    Echar un vistazo a la página de demostración: http://angular-ui.github.com/, de búsqueda de abajo para Validar la partida.

    De la página de demostración:

    <input ng-model="email" ui-validate='{blacklist : notBlackListed}'>
    <span ng-show='form.email.$error.blacklist'>This e-mail is black-listed!</span>

    luego en el controlador:

    function ValidateCtrl($scope) {
      $scope.blackList = ['[email protected]','[email protected]'];
      $scope.notBlackListed = function(value) {
        return $scope.blackList.indexOf(value) === -1;
      };
    }
    • Qué raro que esto no funciona para mí el uso de Angulares 1.4
    • puede confirmar que no funciona para angularjs 1.4.x
  3. 46

    Puede utilizar ng-requiere para su validación escenario («si estos 3 campos están llenos, a continuación, este campo es obligatorio»:

    <div ng-app>
        <input type="text" ng-model="field1" placeholder="Field1">
        <input type="text" ng-model="field2" placeholder="Field2">
        <input type="text" ng-model="field3" placeholder="Field3">
        <input type="text" ng-model="dependentField" placeholder="Custom validation"
            ng-required="field1 && field2 && field3">
    </div>
    • Esto funcionó para mí. Por simple validaciones que depende de otros campos de valores, este es el camino a seguir en lugar de solicitarlo a través de complejas reglas de validaciones
  4. 28

    Puede utilizar Angular-Validador.

    Ejemplo: el uso de una función para validar un campo

    <input  type = "text"
        name = "firstName"
        ng-model = "person.firstName"
        validator = "myCustomValidationFunction(form.firstName)">

    Luego en el controlador que tendría algo como

    $scope.myCustomValidationFunction = function(firstName){ 
       if ( firstName === "John") {
           return true;
        }

    Usted también puede hacer algo como esto:

    <input  type = "text"
            name = "firstName"
            ng-model = "person.firstName"
            validator = "'!(field1 && field2 && field3)'"
            invalid-message = "'This field is required'">

    (donde campo1 campo2 y campo3 son variables del ámbito. También puede ser que desee comprobar si los campos no son iguales a la cadena vacía)

    Si el campo no pasa la validator, a continuación, el campo estará marcado como inválido y el usuario no será capaz de enviar el formulario.

    Para obtener más casos de uso y ejemplos ver: https://github.com/turinggroup/angular-validator

    Descargo de responsabilidad: yo soy el autor de Angular-Validador

  5. 13

    He aquí una buena manera de hacer personalizada expresión comodín validaciones en un formulario (de: Avanzada la validación de formularios con AngularJS y filtros):

    <form novalidate="">  
       <input type="text" id="name" name="name" ng-model="newPerson.name"
          ensure-expression="(persons | filter:{name: newPerson.name}:true).length !== 1">
       <!-- or in your case:-->
       <input type="text" id="fruitName" name="fruitName" ng-model="data.fruitName"
          ensure-expression="(blacklist | filter:{fruitName: data.fruitName}:true).length !== 1">
    </form>
    app.directive('ensureExpression', ['$http', '$parse', function($http, $parse) {
        return {
            require: 'ngModel',
            link: function(scope, ele, attrs, ngModelController) {
                scope.$watch(attrs.ngModel, function(value) {
                    var booleanResult = $parse(attrs.ensureExpression)(scope);
                    ngModelController.$setValidity('expression', booleanResult);
                });
            }
        };
    }]);

    jsFiddle demo (compatible con expresión de nombres y expresiones múltiples)

    Es similar a ui-validate, pero no se necesita de un ámbito específico de la función de validación (este funciona de forma genérica) y por supuesto que no necesita interfaz de usuario.utils de esta manera.

    • Gracias. Muy fresco. Es especialmente útil para aplicar reglas de validación de formularios dinámicos. Sin embargo, todavía se establece el modelo de valor aún no es válido. De todos modos para evitar que se establezca la modelValue si es inválido?
  6. 12

    Recientemente he creado una directiva para permitir la expresión de la invalidación de la forma angular de las entradas. Cualquier válido angular expresión puede ser utilizado, y es compatible con la costumbre de validación de claves utilizando notación de objetos. Probado con angular v1.3.8

            .directive('invalidIf', [function () {
            return {
                require: 'ngModel',
                link: function (scope, elm, attrs, ctrl) {
    
                    var argsObject = scope.$eval(attrs.invalidIf);
    
                    if (!angular.isObject(argsObject)) {
                        argsObject = { invalidIf: attrs.invalidIf };
                    }
    
                    for (var validationKey in argsObject) {
                        scope.$watch(argsObject[validationKey], function (newVal) {
                            ctrl.$setValidity(validationKey, !newVal);
                        });
                    }
                }
            };
        }]);

    Se puede utilizar como esto:

    <input ng-model="foo" invalid-if="{fooIsGreaterThanBar: 'foo > bar',
                                       fooEqualsSomeFuncResult: 'foo == someFuncResult()'}/>

    O simplemente de paso en una expresión (que será dado el valor predeterminado validationKey de «invalidIf»)

    <input ng-model="foo" invalid-if="foo > bar"/>
  7. 5

    Actualización:

    Mejorado y simplificado la versión de la anterior directiva (uno en vez de dos) con la misma funcionalidad:

    .directive('myTestExpression', ['$parse', function ($parse) {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function (scope, element, attrs, ctrl) {
                var expr = attrs.myTestExpression;
                var watches = attrs.myTestExpressionWatch;
    
                ctrl.$validators.mytestexpression = function (modelValue, viewValue) {
                    return expr == undefined || (angular.isString(expr) && expr.length < 1) || $parse(expr)(scope, { $model: modelValue, $view: viewValue }) === true;
                };
    
                if (angular.isString(watches)) {
                    angular.forEach(watches.split(",").filter(function (n) { return !!n; }), function (n) {
                        scope.$watch(n, function () {
                            ctrl.$validate();
                        });
                    });
                }
            }
        };
    }])

    Ejemplo de uso:

    <input ng-model="price1" 
           my-test-expression="$model > 0" 
           my-test-expression-watch="price2,someOtherWatchedPrice" />
    <input ng-model="price2" 
           my-test-expression="$model > 10" 
           my-test-expression-watch="price1" 
           required />

    Resultado: Mutuamente dependientes expresiones de prueba donde los validadores se ejecutan en cambio de otros, la directiva del modelo y el modelo actual.

    De la prueba de expresión local $model variable que se debe utilizar para comparar con otras variables.

    Anteriormente:

    He hecho un intento de mejorar la @Plantface código mediante la adición de la directiva. Este extra directiva muy útil si nuestra expresión debe ser ejecutado cuando se realizan cambios en más de una ngModel variables.

    .directive('ensureExpression', ['$parse', function($parse) {
        return {
            restrict: 'A',
            require: 'ngModel',
            controller: function () { },
            scope: true,
            link: function (scope, element, attrs, ngModelCtrl) {
                scope.validate = function () {
                    var booleanResult = $parse(attrs.ensureExpression)(scope);
                    ngModelCtrl.$setValidity('expression', booleanResult);
                };
    
                scope.$watch(attrs.ngModel, function(value) {
                    scope.validate();
                });
            }
        };
    }])
    
    .directive('ensureWatch', ['$parse', function ($parse) {
        return {
            restrict: 'A',
            require: 'ensureExpression',
            link: function (scope, element, attrs, ctrl) {
                angular.forEach(attrs.ensureWatch.split(",").filter(function (n) { return !!n; }), function (n) {
                    scope.$watch(n, function () {
                        scope.validate();
                    });
                });
            }
        };
    }])

    Ejemplo de cómo utilizarlo para hacer la cruz validado campos:

    <input name="price1"
           ng-model="price1" 
           ensure-expression="price1 > price2" 
           ensure-watch="price2" />
    <input name="price2" 
           ng-model="price2" 
           ensure-expression="price2 > price3" 
           ensure-watch="price3" />
    <input name="price3" 
           ng-model="price3" 
           ensure-expression="price3 > price1 && price3 > price2" 
           ensure-watch="price1,price2" />

    ensure-expression se ejecuta para validar el modelo cuando se ng-model o cualquiera de ensure-watch variables es cambiado.

  8. 4

    @sinérgicos creo que @blesh supongo que para poner la función de validar la siguiente

    function validate(value) {
        var valid = blacklist.indexOf(value) === -1;
        ngModel.$setValidity('blacklist', valid);
        return valid ? value : undefined;
    }
    
    ngModel.$formatters.unshift(validate);
    ngModel.$parsers.unshift(validate);
  9. 3

    En AngularJS el mejor lugar para definir Validación Personalizada es Cutsom directiva.
    AngularJS proporcionar un ngMessages módulo.

    ngMessages es una directiva que está diseñado para mostrar y ocultar mensajes
    sobre la base del estado de una clave/valor del objeto que se escucha. El
    propia directiva complementa notificación de mensajes de error con el ngModel
    $objeto de error (que almacena una clave/valor de estado de los errores de validación).

    Personalizados para la validación del formulario se debe utilizar ngMessages Módulos personalizados con la directiva.Aquí tengo una simple validación en la que se comprobará si la longitud del número es inferior a 6 muestra un error en la pantalla

     <form name="myform" novalidate>
                    <table>
                        <tr>
                            <td><input name='test' type='text' required  ng-model='test' custom-validation></td>
                            <td ng-messages="myform.test.$error"><span ng-message="invalidshrt">Too Short</span></td>
                        </tr>
                    </table>
                </form>

    Aquí es cómo crear una validación personalizada directiva

    angular.module('myApp',['ngMessages']);
            angular.module('myApp',['ngMessages']).directive('customValidation',function(){
                return{
                restrict:'A',
                require: 'ngModel',
                link:function (scope, element, attr, ctrl) {//4th argument contain model information 
    
                function validationError(value) //you can use any function and parameter name 
                    {
                     if (value.length > 6) //if model length is greater then 6 it is valide state
                     {
                     ctrl.$setValidity('invalidshrt',true);
                     }
                     else
                     {
                     ctrl.$setValidity('invalidshrt',false) //if less then 6 is invalide
                     }
    
                     return value; //return to display  error 
                    }
                    ctrl.$parsers.push(validationError); //parsers change how view values will be saved in the model
                }
                };
            });

    $setValidity es consustancial a la función para establecer el modelo de estado válido/no válido

  10. 2

    Las Validaciones personalizadas que llamar a un Servidor

    Utilizar el ngModelController $asyncValidators API que maneja asincrónica de validación, tales como la realización de $http solicitud para el servidor. Funciones de agregado para el objeto debe devolver una promesa que debe ser resuelto cuando se valida o rechaza cuando no válido. En progreso async las validaciones son almacenados por una llave en ngModelController.$pending. Para obtener más información, consulte AngularJS Guía Del Desarrollador – Formularios (Validación Personalizada).

    ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
      var value = modelValue || viewValue;
    
      //Lookup user by username
      return $http.get('/api/users/' + value).
         then(function resolved() {
           //username exists, this means validation fails
           return $q.reject('exists');
         }, function rejected() {
           //username does not exist, therefore this validation passes
           return true;
         });
    };

    Para obtener más información, consulte


    El uso de la $validators API

    La aceptada respuesta utiliza la $parsers y $formatters tuberías para agregar un sincrónica personalizado validador. AngularJS 1.3+ añadido un $validators API así que no hay necesidad de poner los validadores en el $parsers y $formatters tuberías:

    app.directive('blacklist', function (){ 
       return {
          require: 'ngModel',
          link: function(scope, elem, attr, ngModel) {           
              ngModel.$validators.blacklist = function(modelValue, viewValue) {
                  var blacklist = attr.blacklist.split(',');
                  var value = modelValue || viewValue;
                  var valid = blacklist.indexOf(value) === -1;
                  return valid;
              });    
          }
       };
    });

    Para obtener más información, consulte AngularJS ngModelController de Referencia de la API – $validadores.

  11. 1

    Me extendida @Ben Lesh la respuesta con una capacidad para especificar si la validación es sensible a mayúsculas y minúsculas o no (por defecto)

    uso:

    <input type="text" name="fruitName" ng-model="data.fruitName" blacklist="Coconuts,Bananas,Pears" caseSensitive="true" required/>

    código:

    angular.module('crm.directives', []).
    directive('blacklist', [
        function () {
            return {
                restrict: 'A',
                require: 'ngModel',
                scope: {
                    'blacklist': '=',
                },
                link: function ($scope, $elem, $attrs, modelCtrl) {
    
                    var check = function (value) {
                        if (!$attrs.casesensitive) {
                            value = (value && value.toUpperCase) ? value.toUpperCase() : value;
    
                            $scope.blacklist = _.map($scope.blacklist, function (item) {
                                return (item.toUpperCase) ? item.toUpperCase() : item
                            })
                        }
    
                        return !_.isArray($scope.blacklist) || $scope.blacklist.indexOf(value) === -1;
                    }
    
                    //For DOM -> model validation
                    modelCtrl.$parsers.unshift(function (value) {
                        var valid = check(value);
                        modelCtrl.$setValidity('blacklist', valid);
    
                        return value;
                    });
                    //For model -> DOM validation
                    modelCtrl.$formatters.unshift(function (value) {
                        modelCtrl.$setValidity('blacklist', check(value));
                        return value;
                    });
                }
            };
        }
    ]);
  12. 0

    Algunos grandes ejemplos y librerías que se presentan en este hilo, pero no acababa de tener lo que yo estaba buscando. Mi enfoque: angular-validez — una promesa de validación basado en lib para la validación, con la opción de Bootstrap estilo al horno-en.

    Angular de validez de la solución para el OP del caso de uso podría ser algo como esto:

    <input  type="text" name="field4" ng-model="field4"
            validity="eval"
            validity-eval="!(field1 && field2 && field3 && !field4)"
            validity-message-eval="This field is required">

    Aquí un El violín, si quieres dar una vuelta. El lib está disponible en GitHub, ha detallado la documentación, y un montón de demostraciones en vivo.

Dejar respuesta

Please enter your comment!
Please enter your name here