validation - validacion - AngularJS: integración con la validación del lado del servidor
validar pattern angularjs (5)
Tengo una aplicación angular que contiene un botón guardar tomado de los ejemplos:
<button ng-click="save" ng-disabled="form.$invalid">SAVE</button>
Esto funciona muy bien para la validación del lado del cliente porque el form.$invalid
convierte en falso a medida que el usuario soluciona los problemas, pero tengo un campo de correo electrónico que se establece como no válido si otro usuario está registrado con el mismo correo electrónico.
Tan pronto como configure el campo de mi correo electrónico como no válido, no puedo enviar el formulario y el usuario no tiene forma de corregir ese error de validación. Así que ahora ya no puedo usar form.$invalid
para deshabilitar mi botón de envío.
Debe haber una mejor manera
De acuerdo. En caso de que alguien necesite una versión de trabajo, está aquí:
Del doc:
$apply() is used to enter Angular execution context from JavaScript
(Keep in mind that in most places (controllers, services)
$apply has already been called for you by the directive which is handling the event.)
Esto me hizo pensar que no necesitamos: $scope.$apply(function(s) {
De lo contrario, se quejará de $digest
app.directive(''uniqueName'', function($http) {
var toId;
return {
require: ''ngModel'',
link: function(scope, elem, attr, ctrl) {
//when the scope changes, check the name.
scope.$watch(attr.ngModel, function(value) {
// if there was a previous attempt, stop it.
if(toId) clearTimeout(toId);
// start a new attempt with a delay to keep it from
// getting too "chatty".
toId = setTimeout(function(){
// call to some API that returns { isValid: true } or { isValid: false }
$http.get(''/rest/isUerExist/'' + value).success(function(data) {
//set the validity of the field
if (data == "true") {
ctrl.$setValidity(''uniqueName'', false);
} else if (data == "false") {
ctrl.$setValidity(''uniqueName'', true);
}
}).error(function(data, status, headers, config) {
console.log("something wrong")
});
}, 200);
})
}
}
});
HTML:
<div ng-controller="UniqueFormController">
<form name="uniqueNameForm" novalidate ng-submit="submitForm()">
<label name="name"></label>
<input type="text" ng-model="name" name="name" unique-name> <!-- ''unique-name'' because of the name-convention -->
<span ng-show="uniqueNameForm.name.$error.uniqueName">Name is not unique.</span>
<input type="submit">
</form>
</div>
El controlador podría verse así:
app.controller("UniqueFormController", function($scope) {
$scope.name = "Bob"
})
Este es otro caso donde una directiva personalizada es tu amiga. Deberá crear una directiva e inyectar $ http o $ resource en ella para hacer una devolución de llamada al servidor mientras está validando.
Algunos pseudocódigos para la directiva personalizada:
app.directive(''uniqueEmail'', function($http) {
var toId;
return {
restrict: ''A'',
require: ''ngModel'',
link: function(scope, elem, attr, ctrl) {
//when the scope changes, check the email.
scope.$watch(attr.ngModel, function(value) {
// if there was a previous attempt, stop it.
if(toId) clearTimeout(toId);
// start a new attempt with a delay to keep it from
// getting too "chatty".
toId = setTimeout(function(){
// call to some API that returns { isValid: true } or { isValid: false }
$http.get(''/Is/My/EmailValid?email='' + value).success(function(data) {
//set the validity of the field
ctrl.$setValidity(''uniqueEmail'', data.isValid);
});
}, 200);
})
}
}
});
Y así es como lo usarías en el margen:
<input type="email" ng-model="userEmail" name="userEmail" required unique-email/>
<span ng-show="myFormName.userEmail.$error.uniqueEmail">Email is not unique.</span>
EDITAR: una pequeña explicación de lo que está sucediendo arriba.
- Cuando actualiza el valor en la entrada, actualiza el $ scope.userEmail
- La directiva tiene un $ watch en $ scope.userEmail configurado en su función de enlace.
- Cuando se activa el $ watch, realiza una llamada al servidor a través de la llamada $ http ajax, pasando el correo electrónico.
- El servidor verificaría la dirección de correo electrónico y devolvería una respuesta simple como ''{isValid: true}
- esa respuesta se usa para $ setValidity del control.
- Hay un en el marcado con ng-show configurado para mostrar solo cuando el estado de validez de correo electrónico único es falso.
... para el usuario que significa:
- Escriba el correo electrónico.
- pausa leve.
- El mensaje "El correo electrónico no es único" muestra "tiempo real" si el correo electrónico no es único.
EDIT2: Esto también le permite usar form. $ Invalid para deshabilitar su botón de envío.
Gracias a las respuestas de esta página aprendimos sobre https://github.com/webadvanced/ng-remote-validate
Directivas de opciones, que es un poco menos de lo que realmente no me gusta, como cada campo para escribir la directiva. El módulo es el mismo: una solución universal.
Pero en los módulos me faltaba algo: revisa el campo para ver varias reglas.
Luego modifiqué el módulo https://github.com/borodatych/ngRemoteValidate
Disculpas por el LÉEME ruso, eventualmente se alterará.
Me apresuro a compartir de repente tener a alguien con el mismo problema.
Sí, y nos hemos reunido aquí para esto ...
Carga:
<script type="text/javascript" src="../your/path/remoteValidate.js"></script>
Incluir:
var app = angular.module( ''myApp'', [ ''remoteValidate'' ] );
HTML
<input type="text" name="login"
ng-model="user.login"
remote-validate="( ''/ajax/validation/login'', [''not_empty'',[''min_length'',2],[''max_length'',32],''domain'',''unique''] )"
required
/>
<br/>
<div class="form-input-valid" ng-show="form.login.$pristine || (form.login.$dirty && rv.login.$valid)">
From 2 to 16 characters (numbers, letters and hyphens)
</div>
<span class="form-input-valid error" ng-show="form.login.$error.remoteValidate">
<span ng:bind="form.login.$message"></span>
</span>
BackEnd [Kohana]
public function action_validation(){
$field = $this->request->param(''field'');
$value = Arr::get($_POST,''value'');
$rules = Arr::get($_POST,''rules'',[]);
$aValid[$field] = $value;
$validation = Validation::factory($aValid);
foreach( $rules AS $rule ){
if( in_array($rule,[''unique'']) ){
/// Clients - Users Models
$validation = $validation->rule($field,$rule,['':field'','':value'',''Clients'']);
}
elseif( is_array($rule) ){ /// min_length, max_length
$validation = $validation->rule($field,$rule[0],['':value'',$rule[1]]);
}
else{
$validation = $validation->rule($field,$rule);
}
}
$c = false;
try{
$c = $validation->check();
}
catch( Exception $e ){
$err = $e->getMessage();
Response::jEcho($err);
}
if( $c ){
$response = [
''isValid'' => TRUE,
''message'' => ''GOOD''
];
}
else{
$e = $validation->errors(''validation'');
$response = [
''isValid'' => FALSE,
''message'' => $e[$field]
];
}
Response::jEcho($response);
}
He creado Plunker con solución que funciona perfecto para mí. Utiliza directivas personalizadas pero en forma completa y no en un solo campo.
http://plnkr.co/edit/HnF90JOYaz47r8zaH5JY
No recomendaría deshabilitar el botón de enviar para la validación del servidor.
Lo necesitaba en algunos proyectos, así que creé una directiva. Finalmente se tomó un momento para ponerlo en GitHub para cualquiera que quiera una solución de instalación directa.
https://github.com/webadvanced/ng-remote-validate
caracteristicas:
Soltar la solución para la validación Ajax de cualquier entrada de texto o contraseña
Funciona con Angulars compilación en validación y se puede acceder a tax en formName.inputName. $ Error.ngRemoteValidate
Solicitudes de servidor Throttles (400 ms predeterminados) y se pueden establecer con
ng-remote-throttle="550"
Permite la definición del método HTTP (POST por defecto) con
ng-remote-method="GET"
Ejemplo de uso para un formulario de cambio de contraseña que requiere que el usuario ingrese su contraseña actual así como la nueva contraseña .:
<h3>Change password</h3>
<form name="changePasswordForm">
<label for="currentPassword">Current</label>
<input type="password"
name="currentPassword"
placeholder="Current password"
ng-model="password.current"
ng-remote-validate="/customer/validpassword"
required>
<span ng-show="changePasswordForm.currentPassword.$error.required && changePasswordForm.confirmPassword.$dirty">
Required
</span>
<span ng-show="changePasswordForm.currentPassword.$error.ngRemoteValidate">
Incorrect current password. Please enter your current account password.
</span>
<label for="newPassword">New</label>
<input type="password"
name="newPassword"
placeholder="New password"
ng-model="password.new"
required>
<label for="confirmPassword">Confirm</label>
<input ng-disabled=""
type="password"
name="confirmPassword"
placeholder="Confirm password"
ng-model="password.confirm"
ng-match="password.new"
required>
<span ng-show="changePasswordForm.confirmPassword.$error.match">
New and confirm do not match
</span>
<div>
<button type="submit"
ng-disabled="changePasswordForm.$invalid"
ng-click="changePassword(password.new, changePasswordForm);reset();">
Change password
</button>
</div>
</form>