我有一个Angular控制器如下:
function SignUpController($window, accountService) {
var vm = this;
vm.errors = null;
vm.user = null;
vm.submit = function (user) {
accountService.signup(user)
.then(function (response) {
$window.location.href = "/";
})
.catch(function (response) {
vm.errors = response.data.errors;
}
};
}
API会返回错误列表(如果存在),如下所示:
[
{code: "name", "message": "the name is required"}
]
如果有错误,我将此列表添加到vm.errors。在HTML中我有:
<form name="form" ng-controller="SignUpController as vmsignup" ng-submit="vmsignup.submit(vmsignup.user)">
<input ng-model="vmsignup.user.email" name="vmsignup.user.email" type="text" />
<span class="error" validator="vmsignup.user.email"></span>
<!-- Other form fields -->
</form>
该指令正在观察vm.errors并使用验证器填充所有跨度并使用正确的错误消息。
在我的控制器中,我总是使用vm.errors,但在我的html中,我经常使用其他东西,比如vmsignup ,因为我可能有多个控制器。
因此,在此示例中,该指令必须具有vmsignup.errors才能使其正常工作:
angular.module("app").directive("validator", validator);
validator.$inject = ["$parse"];
function validator($parse) {
var validator = {
link: link,
replace: false,
restrict: "A"
};
return validator;
function link(scope, element, attributes) {
scope.$watch("vmsignup.errors", function (errors) {
if (errors) {
var result = errors.filter(function (error) {
if (error.code == null)
return false;
var position = attributes.validator.lastIndexOf(".");
if (position > -1)
return attributes.validator.slice(position + 1).toLowerCase() === error.code.toLowerCase();
else
return attributes.validator.toLowerCase() === error.code.toLowerCase();
});
if (result.length > 0) {
element.show().text(result[0].message);
return;
}
}
element.hide();
});
}
我希望该指令具有类似的内容:
scope.$watch("vm*.errors", ...
我想这是不可能的,但必须有办法解决这个问题,不是吗?
我认为解决方案可能是在表单上使用新的指令“validation”来说明模型是什么:
<form name="form" ng-controller="SignUpController as vmsignup" validation-model="vmsignup">
然后我会在验证器指令上使用它:
scope.$watch(validator.model + ".errors", function (errors) {
这是一个不错的选择吗?可以这样做吗?有人可以帮助我吗?
答案 0 :(得分:0)
您可以将$ watchGroup用于此目的
答案 1 :(得分:0)
您无法在*
表达式中使用$watch
作为通配符,但您可以查看包含$watchCollection
的集合...
一系列属性:
$scope.$watchCollection('[prop1, prop2]', function(newValues, oldValues){
var newProp1 = newValues[0];
var newProp2 = newValues[1];
});
返回值的函数数组:
$scope.$watchCollection([
function(){
return prop1;
}, function(){
return prop2;
}
], function(newValues, oldValues){
var newProp1 = newValues[0];
var newProp2 = newValues[1];
});
<强>更新强>
如@Ambegodas所说,您可以将errors
集合作为参数传递给您的指令。所以你的代码变成了:
angular
.module("app")
.directive("validator", validator);
validator.$inject = ["$parse"];
function validator($parse) {
var validator = {
link: link,
replace: false,
restrict: "A"
};
return validator;
function link(scope, element, attributes) {
scope.$watch(attributes.errors, function (errors) {
if (errors) {
var result = errors.filter(function (error) {
if (error.code == null) return false;
var position = attributes.validator.lastIndexOf(".");
if (position > -1) {
return attributes.validator.slice(position + 1).toLowerCase() === error.code.toLowerCase();
}
return attributes.validator.toLowerCase() === error.code.toLowerCase();
});
if (result.length > 0) {
element.show().text(result[0].message);
return;
}
}
element.hide();
}, true); // << objectEquality == true
}
}
不同的建议方法
您可以为那些只能通过客户端验证验证的输入创建服务器端验证。
HTML:
<form name="form" novalidate ng-submit="vm.submit(vm.account)">
<div class="form-group" mt-show-errors>
<label class="control-label" for="username">Username</label>
<input type="text" mt-validate-username class="form-control" name="username" id="username" ng-model="vm.account.username" required>
<div ng-show="form.$submitted || form.username.$touched">
<span ng-show="form.login.$error.required" class="help-block">Username is required</span>
<span ng-show="form.login.$error.mtValidateUsername" class="help-block">Username already taken</span>
</div>
</div>
<!-- more inputs -->
</form>
指令:
angular
.module('app.directives')
.directive('mtValidateUsername', mtValidateUsername);
function mtValidateUsername($timeout, MyAccountService) {
return {
require: 'ngModel',
scope: false,
link: function (scope, element, attrs, modelCtrl) {
var timeoutId;
modelCtrl.$parsers.push(function (inputValue) {
if (!inputValue) return '';
$timeout.cancel(timeoutId);
timeoutId = $timeout(function () {
MyAccountService.validateUsername(inputValue).then(function () {
modelCtrl.$setValidity('mtValidateUsername', true);
}).catch(function(){
modelCtrl.$setValidity('mtValidateUsername', false);
});
}, 1000); // 1 second throttle
return inputValue;
});
}
};
}
答案 2 :(得分:0)
请尝试以下方法。
var app = angular.module('MyApp',[]);
app.controller('MyCtrl',function($scope){
$scope.errors =1;
$scope.change = function(){
$scope.errors = 2;
}
});
app.directive('myDirecitive',function(){
return {
restrict:'A',
link:linkFunction
}
function linkFunction(scope,element,atrrs){
scope.$watch(atrrs.varName,function(newval,oldval){
console.log("watcher called");
});
}
});
<body ng-app="MyApp", ng-controller="MyCtrl">
<h1>Sample Application</h1>
<input type="text" my-direcitive var-name="errors"/>
<button ng-click="change()">Watch</button>
</body>