AngularJS:与服务器端验证集成

mko*_*yak 55 validation angularjs

我有一个角度应用程序,其中包含从示例中获取的保存按钮:

<button ng-click="save" ng-disabled="form.$invalid">SAVE</button>
Run Code Online (Sandbox Code Playgroud)

这对于客户端验证非常有用,因为form.$invalid当用户修复问题时会变为false,但是如果另一个用户使用相同的电子邮件注册,我的电子邮件字段设置无效.

一旦我将电子邮件字段设置为无效,我就无法提交表单,并且用户无法修复该验证错误.所以现在我不能再form.$invalid用来禁用我的提交按钮了.

肯定有更好的办法

Ben*_*esh 75

这是另一种情况,其中自定义指令是您的朋友.你需要创建一个指令,并在其中注入$ http或$ resource,以便在验证时回调服务器.

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

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);
      })
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

以下是您在标记中使用它的方法:

<input type="email" ng-model="userEmail" name="userEmail" required unique-email/>
<span ng-show="myFormName.userEmail.$error.uniqueEmail">Email is not unique.</span>
Run Code Online (Sandbox Code Playgroud)

编辑:对上面发生的事情的一个小解释.

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

...对用户来说意味着:

  1. 输入电子邮件.
  2. 稍微停顿一下
  3. 如果电子邮件不是唯一的,则"电子邮件不是唯一的"消息显示"实时".

EDIT2:这也允许你使用表单.$ invalid来禁用你的提交按钮.

  • 除此之外,无论如何,当您去保存时,您将需要再次验证您的电子邮件.Web的性质是无状态的,每个请求必须单独验证. (2认同)

Pau*_*aul 30

我在一些项目中需要这个,所以我创建了一个指令.最后花了一点时间把它放在GitHub上,供任何想要一个简单解决方案的人使用.

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

特征:

  • 为任何文本或密码输入的Ajax验证提供解决方案

  • 使用Angulars构建验证,并可以通过formName.inputName访问cab.$ error.ngRemoteValidate

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

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

更改密码表单的示例用法,要求用户输入其当前密码以及新密码:

<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>
Run Code Online (Sandbox Code Playgroud)


And*_*rin 17

我创造了具有适合我的解决方案的plunker.它使用自定义指令,但在整个表单上,而不是在单个字段上.

http://plnkr.co/edit/HnF90JOYaz47r8zaH5JY

我不建议禁用服务器验证的提交按钮.

  • 这非常有帮助!我不得不做一个更改:最新版本没有angular.forEach,所以我更新它以使用$ .each:http://plnkr.co/edit/1UNljzvr70F6O6Tac1R8 (3认同)

ses*_*ses 5

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

来自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.)
Run Code Online (Sandbox Code Playgroud)

这让我觉得我们不需要: $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);
            })
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

控制器可能如下所示:

app.controller("UniqueFormController", function($scope) {
    $scope.name = "Bob"
})
Run Code Online (Sandbox Code Playgroud)