json - vacios - AngularJS-Validación del lado del servidor y formularios del lado del cliente
validar formulario angular 6 (8)
Estoy tratando de entender cómo hacer las siguientes cosas:
¿Cuál es la forma aceptada de declarar un formulario? Según entiendo, solo debe declarar el formulario en HTML y agregar las directivas ng-model de la siguiente manera:
ng-model="item.name"
Qué enviar al servidor. Puedo enviar el objeto del artículo al servidor como JSON e interpretarlo. Entonces puedo realizar la validación en el objeto. Si falla, arrojo un error JSON y le devuelvo exactamente ¿qué? ¿Hay una forma aceptada de hacer esto? ¿Cómo envío los errores de validación del servidor al cliente de una manera agradable?
Realmente necesito un ejemplo, pero los documentos de Angulars son bastante difíciles de entender.
Editar: Parece que he formulado mi pregunta mal.
Sé cómo validar el lado del cliente y cómo manejar el error / éxito como devoluciones de promesas. Lo que quiero saber es la forma aceptada de agrupar los mensajes de error secundarios de SERVER en el cliente. Supongamos que tengo un formulario de registro de nombre de usuario y contraseña. No quiero sondear los nombres de usuario del servidor y luego usar Angular para determinar si existe un duplicado. Deseo enviar el nombre de usuario al servidor, validar que no exista otra cuenta con el mismo nombre y luego enviar el formulario. Si ocurre un error, ¿cómo lo envío?
¿Qué hay de empujar los datos al servidor como es (claves y valores) con un campo de error anexado como así:
{
...data...
"errors": [
{
"context": null,
"message": "A detailed error message.",
"exceptionName": null
}
]
}
Luego vinculando al DOM.
A partir de julio de 2014, AngularJS 1.3 ha agregado nuevas funciones de validación de formularios. Esto incluye ngMessages y asyncValidators, por lo que ahora puede activar la validación del lado del servidor por campo antes de enviar el formulario.
Angular 1.3 Tutorial de validación de formularios :
Referencias
Bueno, la respuesta que dio Derek Ekins es muy buena para trabajar. Pero: si desactiva el botón Enviar con ng-disabled="myForm.$invalid"
, el botón no volverá automáticamente a estar habilitado ya que el estado de error basado en el servidor no parece cambiar. Ni siquiera si edita TODOS los campos en un formulario nuevamente para cumplir con las entradas válidas (según la validación del lado del cliente).
Como variante
// ES6 form controller class
class FormCtrl {
constructor($scope, SomeApiService) {
this.$scope = $scope;
this.someApiService = SomeApiService;
this.formData = {};
}
submit(form) {
if (form.$valid) {
this.someApiService
.save(this.formData)
.then(() => {
// handle success
// reset form
form.$setPristine();
form.$setUntouched();
// clear data
this.formData = {};
})
.catch((result) => {
// handle error
if (result.status === 400) {
this.handleServerValidationErrors(form, result.data && result.data.errors)
} else {// TODO: handle other errors}
})
}
}
handleServerValidationErrors(form, errors) {
// form field to model map
// add fields with input name different from name in model
// example: <input type="text" name="bCategory" ng-model="user.categoryId"/>
var map = {
categoryId: ''bCategory'',
// other
};
if (errors && errors.length) {
// handle form fields errors separately
angular.forEach(errors, (error) => {
let formFieldName = map[error.field] || error.field;
let formField = form[formFieldName];
let formFieldWatcher;
if (formField) {
// tell the form that field is invalid
formField.$setValidity(''server'', false);
// waits for any changes on the input
// and when they happen it invalidates the server error.
formFieldWatcher = this.$scope.$watch(() => formField.$viewValue, (newValue, oldValue) => {
if (newValue === oldValue) {
return;
}
// clean up the server error
formField.$setValidity(''server'', true);
// clean up form field watcher
if (formFieldWatcher) {
formFieldWatcher();
formFieldWatcher = null;
}
});
}
});
} else {
// TODO: handle form validation
alert(''Invalid form data'');
}
}
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 y la nueva contraseña .:Cambia la contraseña
Corriente requerida Contraseña actual incorrecta. Por favor ingrese la contraseña de su cuenta actual.<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>
Por defecto, el formulario se envía normalmente. Si no proporciona una propiedad de nombre para cada campo en el formulario, entonces no enviará los datos correctos. Lo que puede hacer es capturar el formulario antes de enviarlo y enviarlo usted mismo a través de ajax.
<form ng-submit="onSubmit(); return false">
Y luego en su función $scope.onSubmit()
:
$scope.onSubmit = function() {
var data = {
''name'' : $scope.item.name
};
$http.post(url, data)
.success(function() {
})
.failure(function() {
});
};
También puede validar los datos configurando los atributos requeridos.
Si eliges ngResource, se vería así
var Item = $resource(''/items/'');
$scope.item = new Item();
$scope.submit = function(){
$scope.item.$save(
function(data) {
//Yahooooo :)
}, function(response) {
//oh noooo :(
//I''m not sure, but your custom json Response should be stick in response.data, just inspect the response object
}
);
};
Lo más importante es que su código de respuesta HTTP debe ser un 4xx para ingresar la devolución de llamada fallida.
También he estado jugando con este tipo de cosas recientemente y he subido esta demo . Creo que hace lo que necesitas.
Configure su formulario de la forma habitual con las validaciones particulares del lado del cliente que desee utilizar:
<div ng-controller="MyCtrl">
<form name="myForm" onsubmit="return false;">
<div>
<input type="text" placeholder="First name" name="firstName" ng-model="firstName" required="true" />
<span ng-show="myForm.firstName.$dirty && myForm.firstName.$error.required">You must enter a value here</span>
<span ng-show="myForm.firstName.$error.serverMessage">{{myForm.firstName.$error.serverMessage}}</span>
</div>
<div>
<input type="text" placeholder="Last name" name="lastName" ng-model="lastName"/>
<span ng-show="myForm.lastName.$error.serverMessage">{{myForm.lastName.$error.serverMessage}}</span>
</div>
<button ng-click="submit()">Submit</button>
</form>
</div>
Tenga en cuenta también que he agregado un serverMessage
para cada campo:
<span ng-show="myForm.firstName.$error.serverMessage">{{myForm.firstName.$error.serverMessage}}</span>
Este es un mensaje personalizable que proviene del servidor y funciona de la misma manera que cualquier otro mensaje de error (hasta donde yo sé).
Aquí está el controlador:
function MyCtrl($scope, $parse) {
var pretendThisIsOnTheServerAndCalledViaAjax = function(){
var fieldState = {firstName: ''VALID'', lastName: ''VALID''};
var allowedNames = [''Bob'', ''Jill'', ''Murray'', ''Sally''];
if (allowedNames.indexOf($scope.firstName) == -1) fieldState.firstName = ''Allowed values are: '' + allowedNames.join('','');
if ($scope.lastName == $scope.firstName) fieldState.lastName = ''Your last name must be different from your first name'';
return fieldState;
};
$scope.submit = function(){
var serverResponse = pretendThisIsOnTheServerAndCalledViaAjax();
for (var fieldName in serverResponse) {
var message = serverResponse[fieldName];
var serverMessage = $parse(''myForm.''+fieldName+''.$error.serverMessage'');
if (message == ''VALID'') {
$scope.myForm.$setValidity(fieldName, true, $scope.myForm);
serverMessage.assign($scope, undefined);
}
else {
$scope.myForm.$setValidity(fieldName, false, $scope.myForm);
serverMessage.assign($scope, serverResponse[fieldName]);
}
}
};
}
Estoy fingiendo llamar al servidor en pretendThisIsOnTheServerAndCalledViaAjax
puede reemplazarlo con una llamada ajax, el punto es que simplemente devuelve el estado de validación para cada campo. En este caso simple, estoy usando el valor VALID
para indicar que el campo es válido, cualquier otro valor se trata como un mensaje de error. ¡Puede querer algo más sofisticado!
Una vez que tenga el estado de validación del servidor, solo necesita actualizar el estado en su formulario.
Puede acceder al formulario desde el alcance, en este caso el formulario se llama myForm
por lo que $ scope.myForm le proporciona el formulario. (La fuente del controlador de formulario está aquí si desea leer cómo funciona).
A continuación, desea indicarle al formulario si el campo es válido / no válido:
$scope.myForm.$setValidity(fieldName, true, $scope.myForm);
o
$scope.myForm.$setValidity(fieldName, false, $scope.myForm);
También necesitamos configurar el mensaje de error. Antes que nada, obtenga el acceso para el campo usando $ parse. Luego asigne el valor del servidor.
var serverMessage = $parse(''myForm.''+fieldName+''.$error.serverMessage'');
serverMessage.assign($scope, serverResponse[fieldName]);
Espero que ayude
Tengo una solución similar a la de Derek, descrita en el blog codetunes . TL; DR:
muestra un error de forma similar a la solución de Derek:
<span ng-show="myForm.fieldName.$error.server">{{errors.fieldName}}</span>
add directive que eliminaría un error cuando el usuario cambie la entrada:
<input type="text" name="fieldName" ng-model="model.fieldName" server-error /> angular.module(''app'').directive ''serverError'', -> { restrict: ''A'' require: ''?ngModel'' link: (scope, element, attrs, ctrl) -> element.on ''change'', -> scope.$apply -> ctrl.$setValidity(''server'', true) }
Maneje un error pasando el mensaje de error al alcance y diciendo que ese formulario tiene un error:
errorCallback = (result) -> # server will return something like: # { errors: { name: ["Must be unique"] } } angular.forEach result.data.errors, (errors, field) -> # tell the form that field is invalid $scope.form[field].$setValidity(''server'', false) # keep the error messages from the server $scope.errors[field] = errors.join('', '')
Espero que sea útil :)