我正在尝试为电子邮件字段实施表单验证。验证应该执行以下操作:
我希望显示第一条消息,如果该字段为空,则在电子邮件无效且第三条消息出现时显示第二条消息,如果找到该电子邮件地址,因此一次不唯一。
如果我只尝试“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;
}
});
}
};
});
答案 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
答案 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