validar solo reactivos numeros formularios formulario con campos forms angularjs validation

forms - solo - validar formulario angular 6



Comparando dos valores de entrada en una validación de formulario con AngularJS (17)

Estoy tratando de hacer una validación de formulario usando AngularJS. Estoy especialmente interesado en comparar dos valores. Quiero que el usuario confirme algunos datos que ingresó antes de continuar. Digamos que tengo el siguiente código:

<p> Email:<input type="email" name="email1" ng-model="emailReg"> Repeat Email:<input type="email" name="email2" ng-model="emailReg2"> <p>

y luego puedo usar la validación con:

<span ng-show="registerForm.email1.$error.required">Required!</span> <span ng-show="registerForm.email1.$error.email">Not valid email!</span> <span ng-show="emailReg !== emailReg2">Emails have to match!</span> <-- see this line

registerForm. $ valid reaccionará correctamente en cuanto al texto en las entradas, excepto que no sé cómo usar la comparación dentro de esta validación para forzar que los correos electrónicos sean los mismos antes de permitir que el usuario envíe el formulario.

Me encantaría tener una solución sin directivas personalizadas, pero si esto no se puede lograr sin ella, me ocuparé de ello. Here hay una respuesta que aborda un problema similar con una directiva personalizada.

Cualquier ayuda apreciada, gracias


Al actualizar angular a 1.3 y superior, encontré un problema con la gran respuesta de Jacek Ciolek :

  • Agregar datos al campo de referencia
  • Agregue los mismos datos al campo con la directiva (este campo ahora es válido)
  • Vuelva al campo de referencia y cambie los datos (el campo de directiva sigue siendo válido)

Probé la respuesta de rdukeshier (actualizando var modelToMatch = element.attr(''sameAs'') a var modelToMatch = attrs.sameAs para recuperar el modelo de referencia correctamente) pero ocurrió el mismo problema.

Para solucionar esto (probado en angular 1.3 y 1.4), adapté el código de rdukeshier y agregué un observador en el campo de referencia para ejecutar todas las validaciones cuando se cambia el campo de referencia. La directiva ahora se ve así:

angular.module(''app'', []) .directive(''sameAs'', function () { return { require: ''ngModel'', link: function(scope, element, attrs, ctrl) { var modelToMatch = attrs.sameAs; scope.$watch(attrs.sameAs, function() { ctrl.$validate(); }) ctrl.$validators.match = function(modelValue, viewValue) { return viewValue === scope.$eval(modelToMatch); }; } }; });

Códepen actualizado


Aquí está mi versión simple de la directiva del validador personalizado:

angular.module(''app'') .directive(''equalsTo'', function () { return { require: ''ngModel'', link: function (scope, elm, attrs, ngModel) { scope.$watchGroup([attrs.equalsTo, () => ngModel.$modelValue], newVal => { ngModel.$setValidity(''equalsTo'', newVal[0] === newVal[1]); }); } }; })


Aquí hay una versión angular 1.3 de la directiva sameAs:

angular.module(''app'').directive(''sameAs'', [function() { ''use strict''; return { require: ''ngModel'', restrict: ''A'', link: function(scope, element, attrs, ctrl) { var modelToMatch = element.attr(''sameAs''); ctrl.$validators.match = function(modelValue, viewValue) { return viewValue === scope.$eval(modelToMatch); }; } }; }]);


Debería poder usar ng-pattern / regex para comparar 2 valores de entrada

Email:<input type="email" name="email1" ng-model="emailReg"> Repeat Email:<input type="email" name="email2" ng-model="emailReg2" ng-pattern="emailReg">

y validación con:

<span ng-show="registerForm.email2.$error.pattern">Repeat Email should have the same value with email!</span>


El método de @ Henry-Neo estaba cerca, solo necesitaba reglas Regex más estrictas.

<form name="emailForm"> Email: <input type="email" name="email1" ng-model="emailReg"> Repeat Email: <input type="email" name="email2" ng-model="emailReg2" ng-pattern="(emailReg)"> </form>

Al incluir la regla de emailReg emailReg2 entre paréntesis, coincidirá con la cadena completa de emailReg a emailReg2 y hará que la validación del formulario falle porque no coincide.

Luego puede explorar los elementos para descubrir qué parte está fallando.

<p ng-show="emailForm.$valid">Form Valid</p> <p ng-show="emailForm.email1.$error">Email not valid</p> <p ng-show="emailForm.email1.$valid && emailForm.email1.$error.pattern"> Emails Do Not Match </p>


El mío es similar a tu solución, pero lo hice funcionar. La única diferencia es mi modelo. Tengo los siguientes modelos en mi entrada html:

ng-model="new.Participant.email" ng-model="new.Participant.confirmEmail"

y en mi controlador, tengo esto en $ scope:

$scope.new = { Participant: {} };

y esta línea de validación funcionó:

<label class="help-block" ng-show="new.Participant.email !== new.Participant.confirmEmail">Emails must match! </label>


Este módulo funciona bien para comparar dos campos. Funciona muy bien con Angular 1.3+. Fácil de usar https://www.npmjs.com/package/angular-password

También permite guardar el módulo como un genérico. Simplemente inclúyalos en la lista de paquetes de su módulo.


Gracias por el gran ejemplo . Para angular 1.3.x, esta solución se rompe cuando se realizan actualizaciones en el valor de entrada de referencia. Sobre la base de este ejemplo para angular 1.3.x, esta solución funciona igual de bien con Angular 1.3.x. Se une y observa los cambios en el valor de referencia.

angular.module(''app'', []).directive(''sameAs'', function() { return { restrict: ''A'', require: ''ngModel'', scope: { sameAs: ''='' }, link: function(scope, elm, attr, ngModel) { if (!ngModel) return; attr.$observe(''ngModel'', function(value) { // observes changes to this ngModel ngModel.$validate(); }); scope.$watch(''sameAs'', function(sameAs) { // watches for changes from sameAs binding ngModel.$validate(); }); ngModel.$validators.sameAs = function(value) { return scope.sameAs == value; }; } }; });

Aquí está mi pluma: http://codepen.io/kvangrae/pen/BjxMWR


Necesito hacer esto solo en una forma en toda mi aplicación y veo una directiva como una súper complicada para mi caso, así que uso el ng-patter como si tuviera algún punto, pero tengo algunos problemas, cuando la cadena tiene caracteres especiales como .[/ this broke, así que creo una función para scape special characters.

$scope.escapeRegExp(str) { return str.replace(/[/-/[/]///{/}/(/)/*/+/?/.///^/$/|]/g, "//$&"); }

y en la vista

<form name="ExampleForm"> <label>Password</label> <input ng-model="password" required /> <br> <label>Confirm password</label> <input ng-model="confirmPassword" required ng-pattern="escapeRegExp(password)"/> </form>


No necesita una función o una directiva. Simplemente compare su $ modelValue de la vista:

ng-show="formName.email.$modelValue !== formName.confirmEmail.$modelValue"

Un ejemplo más detallado:

<span ng-show="(formName.email.$modelValue !== formName.confirmEmail.$modelValue) && formName.confirmEmail.$touched && !formName.confirmEmail.$error.required">Email does not match.</span>

Tenga en cuenta que ConfirmEmail se encuentra fuera de ViewModel; es propiedad del $ scope. No necesita ser enviado.


Por supuesto, para realizar comparaciones muy simples, siempre puede usar ngMin / ngMax .

De lo contrario, puede ir con una directiva personalizada, y no hay necesidad de hacer $watch o $observe o $eval o esta fantasía $setValidity ida y vuelta. Además, no hay necesidad de enganchar en la función postLink . Trata de mantenerte alejado del DOM tanto como sea posible, ya que está en contra del espíritu angular.

Simplemente use los enganches de ciclo de vida que le da el marco. Agregue un validador y $validate en cada cambio. Simple como eso.

app.directive(''sameAs'', function() { return { restrict: ''A'', require: { ngModelCtrl: ''ngModel'' }, scope: { reference: ''<sameAs'' }, bindToController: true, controller: function($scope) { var $ctrl = $scope.$ctrl; //add the validator to the ngModelController $ctrl.$onInit = function() { function sameAsReference (modelValue, viewValue) { if (!$ctrl.reference || !modelValue) { //nothing to compare return true; } return modelValue === $ctrl.reference; } $ctrl.ngModelCtrl.$validators.sameas = sameAsReference; }; //do the check at each change $ctrl.$onChanges = function(changesObj) { $ctrl.ngModelCtrl.$validate(); }; }, controllerAs: ''$ctrl'' }; });

Tu plunker .


Recientemente escribí una directiva personalizada que puede ser lo suficientemente genérica como para hacer cualquier validación. Toma una función de validación del alcance actual

module.directive(''customValidator'', [function () { return { restrict: ''A'', require: ''ngModel'', scope: { validateFunction: ''&'' }, link: function (scope, elm, attr, ngModelCtrl) { ngModelCtrl.$parsers.push(function (value) { var result = scope.validateFunction({ ''value'': value }); if (result || result === false) { if (result.then) { result.then(function (data) { //For promise type result object ngModelCtrl.$setValidity(attr.customValidator, data); }, function (error) { ngModelCtrl.$setValidity(attr.customValidator, false); }); } else { ngModelCtrl.$setValidity(attr.customValidator, result); return result ? value : undefined; //For boolean result return based on boolean value } } return value; }); } }; }]);

Para usarlo lo haces

<input type="email" name="email2" ng-model="emailReg2" custom-validator=''emailMatch'' data-validate-function=''checkEmailMatch(value)''> <span ng-show="registerForm.email2.$error.emailMatch">Emails have to match!</span>

En tu controlador, entonces puedes implementar el método, que debería devolver verdadero o falso

$scope.checkEmailMatch=function(value) { return value===$scope.emailReg; }

La ventaja es que no tiene que escribir directivas personalizadas para cada validación personalizada.


Tienes que mirar el problema más grande. Cómo escribir las directivas que resuelven un problema. Deberías probar directive use-form-error . Ayudaría a resolver este problema, y ​​muchos otros.

<form name="ExampleForm"> <label>Password</label> <input ng-model="password" required /> <br> <label>Confirm password</label> <input ng-model="confirmPassword" required /> <div use-form-error="isSame" use-error-expression="password && confirmPassword && password!=confirmPassword" ng-show="ExampleForm.$error.isSame">Passwords Do Not Match!</div> </form>

Ejemplo en vivo jsfiddle


Una forma de lograr esto es con una directiva personalizada. Aquí hay un ejemplo usando la directiva ngMatch :

<p>Email:<input type="email" name="email1" ng-model="emailReg"> Repeat Email:<input type="email" name="email2" ng-model="emailReg2" ng-match="emailReg"></p> <span data-ng-show="myForm.emailReg2.$error.match">Emails have to match!</span>

NOTA: Generalmente no se recomienda usar ng- como prefijo para una directiva personalizada porque puede entrar en conflicto con una directiva AngularJS oficial.

Actualizar

También es posible obtener esta funcionalidad sin usar una directiva personalizada:

HTML

<button ng-click="add()></button> <span ng-show="IsMatch">Emails have to match!</span>

Controlador

$scope.add = function() { if ($scope.emailReg != $scope.emailReg2) { $scope.IsMatch=true; return false; } $scope.IsMatch=false; }


trainosais - tienes razón, la validación debe hacerse en un nivel directivo. Es limpio, modular y permite la reutilización del código. Cuando tienes una validación básica como esa en un controlador, la tienes que escribir una y otra vez para diferentes formas. Eso es súper anti-seco.

Hace poco tuve un problema similar y lo resolví con una directiva simple, que se conecta a la canalización de analizadores sintácticos, por lo que se mantiene coherente con la arquitectura angular. El encadenamiento de validadores hace que sea muy fácil de reutilizar y, en mi opinión, debería considerarse la única solución.

Sin más preámbulos, aquí está el marcado simplificado:

<form novalidate="novalidate"> <label>email</label> <input type="text" ng-model="email" name="email" /> <label>email repeated</label> <input ng-model="emailRepeated" same-as="email" name="emailRepeated" /> </form>

Y el código JS:

angular.module(''app'', []) .directive(''sameAs'', function() { return { require: ''ngModel'', link: function(scope, elem, attrs, ngModel) { ngModel.$parsers.unshift(validate); // Force-trigger the parsing pipeline. scope.$watch(attrs.sameAs, function() { ngModel.$setViewValue(ngModel.$viewValue); }); function validate(value) { var isValid = scope.$eval(attrs.sameAs) == value; ngModel.$setValidity(''same-as'', isValid); return isValid ? value : undefined; } } }; });

La directiva se engancha en la tubería del analizador para recibir notificaciones de cualquier cambio en el valor de vista y establecer la validez en base a la comparación del nuevo valor de vista y el valor del campo de referencia. Ese bit es fácil. El truco está oliendo los cambios en el campo de referencia. Para eso, la directiva establece un observador en el valor de referencia y fuerza-dispara la tubería de análisis, para que todos los validadores se ejecuten de nuevo.

Si quieres jugar con él, aquí está mi pluma: http://codepen.io/jciolek/pen/kaKEn

Espero que ayude, Jacek


usa ng-pattern, para que ng-valid y ng-dirty puedan actuar correctamente

Email:<input type="email" name="email1" ng-model="emailReg"> Repeat Email:<input type="email" name="email2" ng-model="emailReg2" ng-pattern="emailReg"> <span ng-show="registerForm.email2.$error.pattern">Emails have to match!</span>


Chandermani método de Chandermani para que sea compatible con Angularjs 1.3 y superior. Migrado de $ analizadores a $ asyncValidators.

module.directive(''customValidator'', [function () { return { restrict: ''A'', require: ''ngModel'', scope: { validateFunction: ''&'' }, link: function (scope, elm, attr, ngModelCtrl) { ngModelCtrl.$asyncValidators[attr.customValidator] = function (modelValue, viewValue) { return new Promise(function (resolve, reject) { var result = scope.validateFunction({ ''value'': viewValue }); if (result || result === false) { if (result.then) { result.then(function (data) { //For promise type result object if (data) resolve(); else reject(); }, function (error) { reject(); }); } else { if (result) resolve(); else reject(); return; } } reject(); }); } } }; }]);

El uso es el mismo