Validation AngularJS:与服务器端验证集成

Validation AngularJS:与服务器端验证集成,validation,angularjs,Validation,Angularjs,我有一个angular应用程序,其中包含一个从示例中选取的保存按钮: <button ng-click="save" ng-disabled="form.$invalid">SAVE</button> 保存 这对于客户端验证非常有效,因为当用户修复问题时,form.$invalid将变为false,但我有一个电子邮件字段,如果其他用户使用相同的电子邮件注册,该字段将设置为无效 一旦我将电子邮件字段设置为无效,我就无法提交表单,用户也无法修复该验证错误。因此,现在我不能

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

<button ng-click="save" ng-disabled="form.$invalid">SAVE</button>
保存
这对于客户端验证非常有效,因为当用户修复问题时,
form.$invalid
将变为false,但我有一个电子邮件字段,如果其他用户使用相同的电子邮件注册,该字段将设置为无效

一旦我将电子邮件字段设置为无效,我就无法提交表单,用户也无法修复该验证错误。因此,现在我不能再使用
表单。$invalid
来禁用我的提交按钮


必须有更好的方法

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

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

app.directive('uniqueEmail',函数($http){
变形虫;
返回{
限制:“A”,
要求:'ngModel',
链接:函数(作用域、元素、属性、控制){
//当范围更改时,请检查电子邮件。
范围$watch(attr.ngModel,function(value){
//如果以前有过尝试,请停止。
如果(toId)清除超时(toId);
//开始一次新的尝试,但要延迟,以防止
//变得太“健谈”。
toId=setTimeout(函数(){
//调用返回{isValid:true}或{isValid:false}的某个API
$http.get('/Is/My/EmailValid?email='+value)。成功(函数(数据){
//设置字段的有效性
ctrl.$setValidity('uniqueEmail',data.isValid);
});
}, 200);
})
}
}
});
下面是您在加价中如何使用它:


电子邮件不是唯一的。
编辑:上面发生的事情的一个小解释

  • 当您更新输入中的值时,它会更新$scope.userEmail
  • 该指令在其链接函数中设置了$scope.userEmail上的$watch。
    • 触发$watch时,它通过$HTTPAjax调用向服务器发出调用,并传递电子邮件
    • 服务器将检查电子邮件地址并返回一个简单的响应,如{isValid:true}
    • 该响应用于设置控件的有效性
  • 标记中存在错误,ng show设置为仅在uniqueEmail有效性状态为false时显示
  • 。。。对用户而言,这意味着:

  • 键入电子邮件
  • 稍微停顿一下
  • 如果电子邮件不唯一,“电子邮件不唯一”消息将显示“实时”

  • EDIT2:这也允许您使用表单。$invalid禁用提交按钮。

    我创建了plunker,其解决方案非常适合我。它使用自定义指令,但用于整个表单,而不是单个字段


    我不建议为服务器验证禁用提交按钮。

    好。如果有人需要工作版本,请点击此处:

    从文件:

     $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(函数){
    ,否则它会抱怨
    $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:


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

    功能:

    • 用于对任何文本或密码输入进行Ajax验证的插件解决方案

    • 使用Angulars内置验证和cab,可在formName.inputName.$error.ngRemoteValidate访问

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

    • 允许使用
      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>
    
    更改密码
    现在的
    要求的
    当前密码不正确。请输入您的当前帐户密码。
    新的
    证实
    新建和确认不匹配
    更改密码
    
    感谢从本页了解到的有关

    选项指令,这比我不太喜欢的稍微少一点,因为每个字段都要编写指令。 模块是相同的-通用解决方案

    但是在模块中,我遗漏了一些东西-检查字段中的一些规则。
    然后我只是修改了模块
    为俄文自述道歉,最终会有所改变。
    我急忙与大家分享突然有人有同样的问题。
    是的,我们聚集在这里就是为了这个

    负载:

    <script type="text/javascript" src="../your/path/remoteValidate.js"></script>
    
    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>
    

    但这并不能真正解决我的问题。他们仍然有可能提交一封非唯一的电子邮件,我仍然必须在服务器端验证它,在这一点上,我仍然必须显示客户端错误,而不是通过此指令?但我离题了,如果他们能够提交一封无效的电子邮件,提交将返回一个错误并标记为表单无效,在这一点上在提交表单之前,他们将被迫使用此指令将电子邮件字段标记为有效。此指令将异步向服务器发送请求,服务器将检查电子邮件,并说明它是否在服务器端唯一……如果不是,将显示验证消息。除此之外,不管怎样,您将希望验证当你要保存电子邮件时,请再次删除它。web的性质是无状态的,每个请求都必须单独验证。这篇文章确实帮助了我。我遇到了完全相同的问题,但我必须对代码进行一些修改。一个限制必须是“A”而不是“E”,scope.apply()抛出了一个异常,说“$digest已在进行中”。因此,我在成功回调中内联了ctrl.setValidity()调用,效果非常好。这非常有帮助!我必须做一个更改:最新版本没有angular.forEach,因此我将其更新为使用$。each:I
    <script type="text/javascript" src="../your/path/remoteValidate.js"></script>
    
    var app = angular.module( 'myApp', [ 'remoteValidate' ] );
    
    <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>
    
    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);
    }