电子邮件表单验证一次一个

时间:2013-03-23 21:11:42

标签: angularjs angularjs-directive

我正在尝试为电子邮件字段实施表单验证。验证应该执行以下操作:

  • 检查是否已通过必填属性输入电子邮件,并在未输入电子邮件时显示消息
  • 检查电子邮件是否具有有效格式(似乎是在没有指定属性的情况下自动完成)并在格式错误时显示消息
  • 检查电子邮件在$ http.get电话上是否唯一,并在发现电子邮件时显示一条消息,因此无法使用

我希望显示第一条消息,如果该字段为空,则在电子邮件无效且第三条消息出现时显示第二条消息,如果找到该电子邮件地址,因此一次不唯一。

如果我只尝试“required”属性,那么这很有效,但是一旦我添加了我的email-available指令属性,它就不再检查电子邮件的格式了,而且email-available指令与所需的一起执行属性。这两条消息都会弹出,但我只希望用户一次看到一条消息。

我正在使用angularjs 1.1.3。

有人可以告诉我,我可能做错了吗?

HTML

<div id="user_mod" class="mod_form" ng-show="userModScreenIsVisible">
<form name="mod_user" novalidate>
    <input type="email" name="email" ng-model="user.email" placeholder="E-Mail" required email-available/>
    <div class="user-help" ng-show="mod_user.email.$dirty && mod_user.email.$invalid">Invalid:
        <span ng-show="mod_user.email.$error.required">Please enter your email.</span>
        <span ng-show="mod_user.email.$error.email">This is not a valid email.</span>
        <span ng-show="mod_user.email.$error.emailAvailable">This email address is already taken.</span>
    </div>
</form>

指令

directive('emailAvailable', function($http) { // available
    return {
        require: 'ngModel',
        link: function(scope, elem, attr, ctrl) {
            ctrl.$parsers.unshift(function(viewValue) {
                ctrl.$setValidity('emailAvailable', false);
                if(viewValue !== "" && typeof viewValue !== "undefined") {
                    console.log("variable is defined");

                    $http.get('/api/user/email/' + viewValue + '/available')
                        .success(function(data, status, headers, config) {
                            console.log(status);
                            ctrl.$setValidity('emailAvailable', true);
                            return viewValue;
                        })
                        .error(function(data, status, headers, config) {
                            console.log("error");
                            ctrl.$setValidity('emailAvailable', false);
                            return undefined;
                        });
                } else {
                    console.log("variable is undefined");
                    ctrl.setValidity('emailAvailable', false);
                    return undefined;
                }
            });
        }
    };
});

3 个答案:

答案 0 :(得分:19)

我知道你已经解决了自己的问题,但我想我可以在这里给你一些提示/建议(我希望):

1)您需要做的就是确保验证器在内置角度验证器push()ctrl.$parsers后运行,而不是{{1它。

2)由于先前运行的验证程序显示它无效(即如果字段已经失效,如果您不想进行Ajax调用),则要使验证程序无法运行。您只需在验证器内的unshift()语句中查看ctrl.$invalid

3)您需要在开始ajax呼叫之前单独呼叫if,并在接收之后使表单无效。这样,在AJAX返回之前,您的表单无效,并说明它是否有效。

4)这可能很小,但除非您添加$setValidity(),否则最初分配给$ scope中对象的值在写入屏幕之前不会被验证。如果您的表单通过路由,ng-repeat或ng-include动态添加到屏幕,并且预先填充了数据,则可能会出现问题。通常所有验证器都应该有一个$ parser组件(view - &gt; model)和一个$ formatter组件(model - &gt; view)。

5)谨慎一点。如果模型无效,大多数验证器都将完全删除模型中的值。因为你正在进行异步调用,所以你必须立即在你的解析器函数中返回viewValue。如果字段无效,解析器函数通常会返回ctrl.$formatter,这会阻止无效数据出现在您的模型中。

6)由于验证器具有在$ error对象中维护的状态,因此在最初命中此异步验证器时,您需要清除它。见下文。

7)旁注:在你的回答中,我注意到你在ajax响应处理程序中返回了值......这对你没有任何作用。因为调用是异步的,所以你总是从该解析器返回undefined。它会更新你的型号吗?如果有的话,我会感到惊讶。

以下是我如何更改您的原始指令以使其按您所希望的那样工作:

undefined

And... of course, here is a plunker demonstrating it all

答案 1 :(得分:2)

我通过删除所需的属性并添加第二个名为email-valid的指令解决了这个问题。我还删除了emailAvailable指令的else子句中的setValidity方法。

<强> HTML

<form name="mod_user" novalidate>
    <input type="email" name="email" ng-model="user.email" placeholder="E-Mail" email-valid email-available/>
    <div class="user-help" ng-show="mod_user.email.$dirty && mod_user.email.$invalid">Invalid:
        <span ng-show="mod_user.email.$error.emailValid">Please enter a valid email address.</span>
        <span ng-show="mod_user.email.$error.emailAvailable">This email address is already taken.</span>
    </div>
    <br/>
    <button class="button" ng-click="hideUserModScreen()">Close</button>
    <button class="button" ng-click="updateUserDetails()" ng-disabled="mod_user.$invalid" ng-show="updateUserDetailsButtonIsVisible">Update</button>
    <button class="button" ng-click="saveUserDetails()" ng-disabled="mod_user.$invalid" ng-show="saveUserDetailsButtonIsVisible">Save</button>
</form>

<强>指令

angular.module('myApp.directives', []).
directive('appVersion', ['version', function (version) {
    return function (scope, elm, attrs) {
        elm.text(version);
    };
}]).

directive('emailAvailable', function($http) { // available
    return {
        require: 'ngModel',
        link: function(scope, elem, attr, ctrl) {
            ctrl.$parsers.unshift(function(viewValue) {
                if(viewValue && viewValue.match(/[a-z0-9\-_]+@[a-z0-9\-_]+\.[a-z0-9\-_]{2,}/)) {
                    console.log("variable is defined");

                    $http.get('/api/user/email/' + viewValue + '/available')
                        .success(function(data, status, headers, config) {
                            console.log(status);
                            ctrl.$setValidity('emailAvailable', true);
                            return viewValue;
                        })
                        .error(function(data, status, headers, config) {
                            console.log("error");
                            ctrl.$setValidity('emailAvailable', false);
                            return undefined;
                        });
                } else {
                    console.log("variable is undefined");
                    return undefined;
                }
            });
        }
    };
}).

directive('emailValid', function() {
    return {
        require: 'ngModel',
        link: function(scope, elm, attrs, ctrl) {
            ctrl.$parsers.unshift(function(viewValue) {
                if (viewValue && viewValue.match(/[a-z0-9\-_]+@[a-z0-9\-_]+\.[a-z0-9\-_]{2,}/)) {
                    // it is valid
                    ctrl.$setValidity('emailValid', true);
                    return viewValue;
                } else {
                    // it is invalid, return undefined (no model update)
                    ctrl.$setValidity('emailValid', false);
                    return undefined;
                }
            });
        }
    };
});

答案 2 :(得分:0)

我通过添加超时来延长Ben Lesh的答案,以便它不会检查每次按键

app.directive "uniqueEmail", ($http, $timeout) ->
    restrict: "A" 
    require: "ngModel" 
    link: (scope, elem, attrs, ctrl) ->
        return unless ctrl 
        q = null
        ctrl.$parsers.push (viewValue) ->
            ctrl.$setValidity 'unique-email', true
            if ctrl.$valid
                if viewValue?
                    $timeout.cancel(q) if q?
                    q = $timeout (->
                        ctrl.$setValidity 'checking-unique-email', false
                        $http.get("#{endpoint}/emails/#{viewValue}/exists").success (exists) ->
                            ctrl.$setValidity 'checking-unique-email', true
                            ctrl.$setValidity 'unique-email', exists is 'false'
                        q = null
                        ) , attrs.checkDelay ? 1000

            viewValue