AngularJS:与服务器端validation集成

我有一个angular度的应用程序,其中包含从示例中取得的保存button:

<button ng-click="save" ng-disabled="form.$invalid">SAVE</button> 

这对于客户端validation非常有效,因为当用户修复问题时, form.$invalid变成false,但是如果其他用户使用同一个电子邮件注册,那么我设置了一个无效的email字段。

只要我设置我的电子邮件字段无效,我不能提交表单,用户无法解决validation错误。 所以现在我不能再使用form.$invalid来禁用我的提交button。

一定有更好的办法

我需要一些项目,所以我创build了一个指令。 最后花了一些时间在GitHub上为任何想要一个解决scheme的人提供帮助。

https://github.com/webadvanced/ng-remote-validate

特征:

  • 解决任何文本或密码input的Ajaxvalidation解决scheme

  • 与Angulars一起构buildvalidation,并通过formName.inputName访问cab。$ error.ngRemoteValidate

  • 限制服务器请求(默认为400毫秒),可以使用ng-remote-throttle="550"

  • 允许使用ng-remote-method="GET" HTTP方法定义(默认POST)

更改密码表单的示例用法,需要用户input其当前密码以及新密码。

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

这是自定义指令是你的朋友的另一种情况。 您将需要创build一个指令,并在其中注入$ http或$ resource,以便在validation时回拨给服务器。

自定义指令的一些伪代码:

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

下面是你如何使用它的标记:

 <input type="email" ng-model="userEmail" name="userEmail" required unique-email/> <span ng-show="myFormName.userEmail.$error.uniqueEmail">Email is not unique.</span> 

编辑:上面发生了什么的一个小解释。

  1. 在更新input中的值时,它会更新$ scope.userEmail
  2. 该指令在$ scope.userEmail中设置了$ watch,它在链接函数中设置。
    • 当$ watch被触发时,它通过$ http ajax调用来向服务器发送调用消息,并传递该消息
    • 服务器将检查电子邮件地址并返回一个简单的响应,如“{isValid:true}
    • 该响应用于控制的$ setValidity。
  3. 在ng-show设置的标记中只有当uniqueEmail有效性状态为false时才显示。

对用户来说意味着:

  1. input电子邮件。
  2. 轻微的停顿。
  3. 如果电子邮件不是唯一的,则“电子邮件不是唯一的”消息显示“实时”。

EDIT2:这也允许你使用表单。$无效来禁用你的提交button。

我已经创build了一个完美的解决scheme。 它使用自定义指令,但在整个表单上,而不是在单个字段上。

http://plnkr.co/edit/HnF90JOYaz47r8zaH5JY

我不会build议禁用服务器validation提交button。

好。 如果有人需要工作版本,这是在这里:

从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.) 

这让我觉得我们不需要: $scope.$apply(function(s) {否则它会抱怨$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> 

控制器可能看起来像这样:

 app.controller("UniqueFormController", function($scope) { $scope.name = "Bob" }) 

感谢从这个页面的答案了解到有关https://github.com/webadvanced/ng-remote-validate

选项指令,这比我不是真的很喜欢,因为每个领域写指令。 模块是一样的 – 一个通用的解决scheme。

但是在模块中,我错过了一些东西 – 查看几条规则。
然后我只是修改模块https://github.com/borodatych/ngRemoteValidate
俄文README的道歉最终会改变。
我急于分享突然有人有同样的问题。
是的,我们在这里聚集了这个…

加载:

 <script type="text/javascript" src="../your/path/remoteValidate.js"></script> 

包括:

 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> 

后端[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); }