AngularJS-проверка на стороне сервера и формы на стороне клиента
Я пытаюсь понять, как сделать следующие вещи:
каков принятый способ объявления формы. Насколько я понимаю, вы просто объявляете форму в HTML и добавляете директивы ng-model следующим образом:
ng-model="item.name"
что отправить на сервер. Я могу просто отправить объект item на сервер как JSON и интерпретировать его. Затем я могу выполнить проверку на объекте. Если это не удается, я бросаю ошибку JSON и отправляю обратно что именно? Есть ли общепринятый способ сделать это? Как я могу отправить ошибки проверки с сервера на клиент хорошим способом?
мне действительно нужен пример, но Angulars docs довольно трудно понять.
Edit: кажется, я сформулировал свой вопрос плохо.
Я знаю, как проверить клиентскую сторону, и как обрабатывать ошибки/успех в качестве обещания обратных вызовов. То, что я хочу знать, - это принятый способ связывания сообщений об ошибках на стороне сервера с клиентом. Скажем, у меня есть форма регистрации имени пользователя и пароля. Я не хотите опросить сервер для имен пользователей, а затем использовать Angular для определения дубликата существует. Я хочу отправить имя пользователя на сервер, проверить, что нет другой учетной записи с тем же именем, а затем отправить форму. Если возникает ошибка, как я могу отправить его обратно?
Как насчет отправки данных на сервер как есть (ключи и значения) с полем ошибки, добавленным следующим образом:
{
...data...
"errors": [
{
"context": null,
"message": "A detailed error message.",
"exceptionName": null
}
]
}
затем привязка к DOM.
8 ответов:
я также играл вокруг с такого рода вещи в последнее время, и я залетел демо. Я думаю, что он делает то, что вам нужно.
настройте свою форму в соответствии с обычными проверками на стороне клиента, которые вы хотите использовать:
<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>
Примечание также я добавил
serverMessage
для каждого поля:<span ng-show="myForm.firstName.$error.serverMessage">{{myForm.firstName.$error.serverMessage}}</span>
это настраиваемое сообщение, которое возвращается с сервера и работает так же, как и любое другое сообщение об ошибке (насколько Я могу сказать).
вот контроллер:
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]); } } }; }
я делаю вид, что вызываю сервер в
pretendThisIsOnTheServerAndCalledViaAjax
вы можете заменить его вызовом ajax, дело в том, что он просто возвращает состояние проверки для каждого поля. В этом простом случае я использую значениеVALID
чтобы указать, что поле является допустимым, любое другое значение рассматривается как сообщение об ошибке. Вы можете захотеть что-то более сложное!как только у вас есть состояние проверки с сервера вам просто нужно чтобы обновить состояние в форме.
вы можете получить доступ к форме из области видимости, в этом случае форма называется
myForm
so $ scope.ссылки получает вас форме. (Источник для контроллер формы здесь если вы хотите прочитать о том, как он работает).затем вы хотите сообщить форме, является ли поле допустимым / недопустимым:
$scope.myForm.$setValidity(fieldName, true, $scope.myForm);
или
$scope.myForm.$setValidity(fieldName, false, $scope.myForm);
нам также нужно установить сообщение об ошибке. Прежде всего получить аксессор для поля используя $разбора. Затем назначьте значение с сервера.
var serverMessage = $parse('myForm.'+fieldName+'.$error.serverMessage'); serverMessage.assign($scope, serverResponse[fieldName]);
надеюсь, что это поможет
у меня есть аналогичное решение, как Дерек, описанные на codetunes blog. TL; DR:
отобразить ошибку так же, как в решении Дерека:
<span ng-show="myForm.fieldName.$error.server">{{errors.fieldName}}</span>
добавить директиву, которая будет очищать ошибку при изменении пользователем ввода:
<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) }
обработайте ошибку, передав сообщение об ошибке в область и сообщив, что форма имеет ошибка:
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(', ')
надеюсь, что это будет полезно :)
Ну, ответ Дерек Экинс дал очень приятно работать. Но: если вы отключите кнопку отправки с
ng-disabled="myForm.$invalid"
- кнопка не будет автоматически возвращаться к включенному, поскольку состояние ошибки на основе сервера, похоже, не изменяется. Даже если вы снова отредактируете все поля в форме, чтобы соответствовать допустимым входным данным (на основе проверки на стороне клиента).
по умолчанию форма представляется в обычном режиме. Если вы не предоставите свойство name для каждого поля в форме, то он не будет отправлять правильные данные. Что вы можете сделать, это захватить форму до ее отправки и отправить эти данные самостоятельно через ajax.
<form ng-submit="onSubmit(); return false">
и затем в
$scope.onSubmit()
функция:$scope.onSubmit = function() { var data = { 'name' : $scope.item.name }; $http.post(url, data) .success(function() { }) .failure(function() { }); };
вы также можете проверить данные, настроив необходимые атрибуты.
Если вы выберете ngResource, это будет выглядеть так
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 } ); };
самое главное, что ваш код HTTP-ответа должен быть 4xx, чтобы ввести обратный вызов сбоя.
по состоянию на июль 2014 года, AngularJS 1.3 добавил новые функции проверки формы. Это включает в себя ngMessages и asyncValidators, так что теперь вы можете запустить проверку на стороне сервера в поле перед отправкой формы.
угловой 1.3 форма проверки учебник:
ссылки:
мне это было нужно в нескольких проектах, поэтому я создал директиву. Наконец, потребовалось время, чтобы поместить его на GitHub для всех, кто хочет получить решение для ввода.
https://github.com/webadvanced/ng-remote-validate
характеристики:
падение в решении для проверки Ajax любого ввода текста или пароля
работы с ангулярами строят в утверждении и кабина была достигана на имя формы.inputName.$ошибка.ngRemoteValidate
регулирует запросы сервера (по умолчанию 400 мс) и может быть установлен с
ng-remote-throttle="550"
позволяет определение метода HTTP (по умолчанию POST) с
ng-remote-method="GET"
Пример использования для формы изменения пароля, которая требует от пользователя ввести свой текущий пароль, а также новый пароль.:смена пароля
Текущий Требуемый Неверный текущий пароль. Пожалуйста, введите пароль вашего текущего счета.<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>
Как вариант
// 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'); } }