我有一个角度应用程序,其中包含一个取自示例的保存按钮:
<button ng-click="save" ng-disabled="form.$invalid">SAVE</button>
这适用于客户端验证,因为form.$invalid
因用户修复问题而变为false,但是如果另一个用户使用相同的电子邮件注册,我的电子邮件字段设置无效。
只要我将电子邮件字段设置为无效,我就无法提交表单,并且用户无法修复该验证错误。所以现在我不能再使用form.$invalid
来禁用我的提交按钮了。
必须有更好的方法
答案 0 :(得分:74)
另一种情况是自定义指令是你的朋友。您需要创建一个指令,并在其中注入$ 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);
})
}
}
});
以下是您在标记中使用它的方法:
<input type="email" ng-model="userEmail" name="userEmail" required unique-email/>
<span ng-show="myFormName.userEmail.$error.uniqueEmail">Email is not unique.</span>
编辑:对上面发生的事情的一个小解释。
...对用户来说意味着:
EDIT2:这也允许您使用表单。$ invalid来禁用您的提交按钮。
答案 1 :(得分:30)
我在一些项目中需要这个,所以我创建了一个指令。最后花了一点时间把它放在GitHub上,供那些想要一个直接解决方案的人使用。
https://github.com/webadvanced/ng-remote-validate
功能强>
为任何文本或密码输入的Ajax验证提供解决方案
使用Angulars构建验证,并可通过formName.inputName访问cab。$ error.ngRemoteValidate
Throttles服务器请求(默认为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>
答案 2 :(得分:17)
我创造了具有适合我的解决方案的plunker。它使用自定义指令,但在整个表单上,而不是在单个字段上。
http://plnkr.co/edit/HnF90JOYaz47r8zaH5JY
我不建议禁用服务器验证的提交按钮。
答案 3 :(得分: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.)
这让我觉得我们不需要:$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"
})
答案 4 :(得分:3)
感谢此页面的回答了解了https://github.com/webadvanced/ng-remote-validate
选项指令,它比我不喜欢的略少,因为每个字段都要写指令。 模块是相同的 - 一个通用的解决方案。
但是在模块中我遗漏了一些东西 - 检查几个规则的字段
然后我只修改了模块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>
BackEnd [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);
}