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>
编辑:上面发生了什么的一个小解释。
- 在更新input中的值时,它会更新$ scope.userEmail
- 该指令在$ scope.userEmail中设置了$ watch,它在链接函数中设置。
- 当$ watch被触发时,它通过$ http ajax调用来向服务器发送调用消息,并传递该消息
- 服务器将检查电子邮件地址并返回一个简单的响应,如“{isValid:true}
- 该响应用于控制的$ setValidity。
- 在ng-show设置的标记中只有当uniqueEmail有效性状态为false时才显示。
对用户来说意味着:
- input电子邮件。
- 轻微的停顿。
- 如果电子邮件不是唯一的,则“电子邮件不是唯一的”消息显示“实时”。
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); }