validar solo reactivos numeros formularios formulario con campos angularjs

solo - ¿Cómo agregar validación personalizada a un formulario AngularJS?



validar formulario angular 6 (12)

Validaciones personalizadas que llaman a un servidor

Use la API ngModelController $asyncValidators que maneja la validación asíncrona, como hacer una solicitud $http al backend. Las funciones agregadas al objeto deben devolver una promesa que debe resolverse cuando sea válida o rechazada cuando sea inválida. Las validaciones asíncronas en curso se almacenan por clave en ngModelController.$pending . Para obtener más información, consulte la Guía del desarrollador de AngularJS - 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 más información, ver

Tengo un formulario con campos de entrada y configuración de validación agregando los atributos required y demás. Pero para algunos campos necesito hacer alguna validación extra. ¿Cómo podría "aprovechar" la validación que controla FormController ?

La validación personalizada podría ser algo así como "si estos 3 campos se completan, entonces este campo es obligatorio y se debe formatear de una manera particular".

Hay un método en FormController.$setValidity pero no parece una API pública, así que prefiero no usarlo. Crear una directiva personalizada y utilizar NgModelController parece otra opción, pero básicamente me obligaría a crear una directiva para cada regla de validación personalizada, que no deseo.

En realidad, marcar un campo desde el controlador como no válido (mientras que también mantiene sincronizado a FormController ) podría ser lo que necesito en el escenario más simple para hacer el trabajo, pero no sé cómo hacerlo.


@synergetic Creo que @blesh supone que se debe validar la función como se muestra a continuación

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);


Algunos ejemplos y libs excelentes presentados en este hilo, pero no tenían exactamente lo que estaba buscando. Mi enfoque: angular-validity : una promesa de validación basada en lib para validación asíncrona, con un estilo Bootstrap opcional incorporado.

Una solución de validez angular para el caso de uso del OP podría tener este aspecto:

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

Aquí hay un Fiddle , si quieres probarlo. La biblioteca está disponible en angular-validity , tiene documentación detallada y muchas demostraciones en vivo.


El proyecto de Angular-UI incluye una directiva ui-validate, que probablemente le ayudará con esto. Te permite especificar una función a la que llamar para hacer la validación.

Eche un vistazo a la página de demostración: http://angular-ui.github.com/ , busque el encabezado Validar.

Desde 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>

entonces en su controlador:

function ValidateCtrl($scope) { $scope.blackList = [''[email protected]'',''[email protected]'']; $scope.notBlackListed = function(value) { return $scope.blackList.indexOf(value) === -1; }; }


En AngularJS, el mejor lugar para definir la validación personalizada es la directiva Cutsom. AngularJS proporciona un módulo ngMessages.

ngMessages es una directiva que está diseñada para mostrar y ocultar mensajes según el estado de un objeto clave / valor en el que escucha. La directiva en sí complementa los informes de mensajes de error con el objeto de error ngModel $ (que almacena un estado clave / valor de errores de validación).

Para la validación de formularios personalizados, se deben usar ngMessages Modules con una directiva personalizada. Aquí tengo una validación simple que verificará si la longitud del número es menor a 6 y aparece 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 directiva de validación personalizada.

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 una función incorporada para establecer el estado del modelo como válido / no válido


Esta es una manera excelente de realizar validaciones de expresiones de comodín personalizadas en un formulario (desde: Validación avanzada 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); }); } }; }]);

Demostración de jsFiddle (soporta nombres de expresiones y expresiones múltiples)

Es similar a ui-validate , pero no necesita una función de validación específica del alcance (esto funciona de forma genérica) y, por supuesto, no necesita ui.utils de esta manera.


Extendí la respuesta de @Ben Lesh con la capacidad de especificar si la validación distingue entre mayúsculas y minúsculas (predeterminado)

utilizar:

<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; }); } }; } ]);


Puede usar ng-required para su escenario de validación ("si se completan estos 3 campos, entonces 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>


Puedes usar Angular-Validator .

Ejemplo: usar una función para validar un campo

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

Entonces en tu control tendrías algo como

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

También puedes hacer algo como esto:

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

(donde field1 field2 y field3 son variables de alcance. También es posible que desee comprobar si los campos no son iguales a la cadena vacía)

Si el campo no pasa el validator , el campo se marcará como no válido y el usuario no podrá enviar el formulario.

Para más casos de uso y ejemplos, consulte: Angular-Validator

Descargo de responsabilidad: Soy el autor de Angular-Validator


Recientemente creé una directiva para permitir la invalidación basada en expresiones de las entradas de forma angular. Se puede usar cualquier expresión angular válida, y admite claves de validación personalizadas mediante notación de objetos. Probado con v1.3.8 angular

.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); }); } } }; }]);

Puedes usarlo así:

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

O simplemente pasando una expresión (se le dará la clave de validación predeterminada de "invalidIf")

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


Actualizar:

Versión mejorada y simplificada de la directiva anterior (una en lugar 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: expresiones de prueba mutuamente dependientes donde los validadores se ejecutan al cambiar el modelo de directivas de otros y el modelo actual.

La expresión de prueba tiene una variable de $model local que debe usar para compararla con otras variables.

Previamente:

Intenté mejorar el código de @Plantface agregando una directiva adicional. Esta directiva adicional es muy útil si nuestra expresión necesita ejecutarse cuando se realizan cambios en más de una variable ngModel.

.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 usarlo para hacer campos de validación cruzada:

<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 cambia ng-model o cualquiera de ensure-watch variables ensure-watch .


Edición: se agregó información sobre ngMessages (> = 1.3.X) a continuación.

Mensajes de validación de formulario estándar (1.0.X y superior)

Dado que este es uno de los mejores resultados si realiza una "Validación de Formulario Angular" en Google, actualmente, quiero agregar otra respuesta a esto para cualquiera que venga de allí.

Hay un método en FormController. $ SetValidity pero no parece una API pública, así que prefiero no usarlo.

Es "público", no te preocupes. Utilízalo Para eso está. Si no estuviera destinado a ser utilizado, los desarrolladores de Angular lo habrían privatizado en un cierre.

Para realizar la validación personalizada, si no desea utilizar la interfaz de usuario angular como la otra respuesta sugerida, simplemente puede aplicar su propia directiva de validación.

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 aquí hay algunos ejemplos 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 probable que sea preferible sustituir ng-if por ng-show anterior

Aquí hay un enlace obligatorio plunker

Además, he escrito algunas entradas de blog sobre este tema que se detallan un poco más:

Validación De Forma Angular

Directivas de validación personalizadas

Edición: utilizando ngMessages en 1.3.X

Ahora puede usar el módulo ngMessages en lugar de ngShow para mostrar sus mensajes de error. Realmente funcionará con cualquier cosa, no tiene que ser un mensaje de error, pero aquí están los conceptos básicos:

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

    var app = angular.module(''myApp'', [''ngMessages'']);

  3. Agregue el marcado apropiado:

    <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 marcado anterior, ng-message="personForm.email.$error" básicamente especifica un contexto para las directivas secundarias de ng-message . Luego, ng-message="required" y ng-message="email" especifican las propiedades en ese contexto para ver. Lo más importante es que también especifican una orden para registrarlos . El primero que encuentre en la lista que es "sincero" gana, y mostrará ese mensaje y ninguno de los otros.

Y un plunker para el ejemplo ngMessages