I've created a validation directive for my form. It basically validates a fields value based on data from another field.
我已经为我的表单创建了一个验证指令。它基本上根据来自另一个字段的数据验证字段值。
It works perfect :-)
它完美无缺:-)
My problem is that if the other field changes after the validation was executed, the validation will not run again.
我的问题是,如果在执行验证后其他字段发生更改,则验证将不再运行。
var myApp = angular.module('myApp', [])
.directive('validateInteger', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
var int1val = scope.int1;
scope.int2valid = (viewValue > int1val) ? "valid" : undefined;
if (scope.int2valid == "valid") {
ctrl.$setValidity('higher', true);
return viewValue;
} else {
ctrl.$setValidity('higher', false);
return undefined;
}
});
}
};
});
jsfiddle: http://jsfiddle.net/hanspc/vCFFQ/
2 个解决方案
#1
3
It is a really bad idea to refer explicitly to some fields in your directive. As you can see, this has a lot of drawbacks : unportability, code repetition, brittleness, …
明确引用指令中的某些字段是一个非常糟糕的主意。正如您所看到的,这有很多缺点:不可移植性,代码重复,脆弱性,......
Just make something like that :
做这样的事情:
<input type="text" ng-model="int2" validate-greater-integer="int1" />
And :
myApp.directive('validateGreaterInteger', function() {
return {
require: 'ngModel',
scope: {
otherInteger : '=validateGreaterInteger',
}
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
if (viewValue > scope.otherInteger) {
ctrl.$setValidity('higher', true);
return viewValue;
} else {
ctrl.$setValidity('higher', false);
return undefined;
}
}
});
You can then simply do the typical state control (see the section "Binding to form and control state" for an exemple).
然后,您可以简单地执行典型的状态控制(有关示例,请参阅“绑定到窗体和控件状态”一节)。
Please notice that, in this case, you can also more simply use input[number] and its min
parameter.
请注意,在这种情况下,您还可以更简单地使用input [number]及其min参数。
Edit after the discussion in comments :
在评论讨论后编辑:
Well, the functions in NgModelController.$parsers
are obviously called only when the content of the model changes. What you want to do is to make validation whenever int1
or int2
change. So just do it :-) :
好吧,NgModelController。$解析器中的函数显然只在模型内容发生变化时才被调用。你想要做的是在int1或int2改变时进行验证。所以就这样做:-):
link: function(scope, elm, attrs, ctrl) {
scope.$watch('data', function (data) {
if (data.int2 > data.int1) {
ctrl.$setValidity('higher', true);
return data.int2;
} else {
ctrl.$setValidity('higher', false);
return undefined;
}
}, true);
Use your own validation variable (int2valid
in your Fiddle) is also very strange. Please use the typical state control, with something like form.int2.$error.higher
.
使用你自己的验证变量(你的小提琴中的int2valid)也很奇怪。请使用典型的状态控件,例如form.int2。$ error.higher。
#2
2
Maybe a simpler solution would be with a watcher or even an expression inside the ng-show direcive of your error span.
也许一个更简单的解决方案可能是观察者甚至是你的错误范围的ng-show方向内的表达。
Using an expression inside the ng-show directive would be like this:
使用ng-show指令中的表达式将是这样的:
<span ng-show="int1 > int2" style="color: red; display:none">
Otherwise you could watch for changes in the models int1 and int2 and compare their values:
否则,您可以观察模型int1和int2中的更改并比较它们的值:
$scope.$watch('int1+int2', function () {
if($scope.int1 > $scope.int2) {
$scope.error = true;
}else {
$scope.error = false;
}
})
<span ng-show="error" style="color: red; display:none">
Here is a fiddle
这是一个小提琴
#1
3
It is a really bad idea to refer explicitly to some fields in your directive. As you can see, this has a lot of drawbacks : unportability, code repetition, brittleness, …
明确引用指令中的某些字段是一个非常糟糕的主意。正如您所看到的,这有很多缺点:不可移植性,代码重复,脆弱性,......
Just make something like that :
做这样的事情:
<input type="text" ng-model="int2" validate-greater-integer="int1" />
And :
myApp.directive('validateGreaterInteger', function() {
return {
require: 'ngModel',
scope: {
otherInteger : '=validateGreaterInteger',
}
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
if (viewValue > scope.otherInteger) {
ctrl.$setValidity('higher', true);
return viewValue;
} else {
ctrl.$setValidity('higher', false);
return undefined;
}
}
});
You can then simply do the typical state control (see the section "Binding to form and control state" for an exemple).
然后,您可以简单地执行典型的状态控制(有关示例,请参阅“绑定到窗体和控件状态”一节)。
Please notice that, in this case, you can also more simply use input[number] and its min
parameter.
请注意,在这种情况下,您还可以更简单地使用input [number]及其min参数。
Edit after the discussion in comments :
在评论讨论后编辑:
Well, the functions in NgModelController.$parsers
are obviously called only when the content of the model changes. What you want to do is to make validation whenever int1
or int2
change. So just do it :-) :
好吧,NgModelController。$解析器中的函数显然只在模型内容发生变化时才被调用。你想要做的是在int1或int2改变时进行验证。所以就这样做:-):
link: function(scope, elm, attrs, ctrl) {
scope.$watch('data', function (data) {
if (data.int2 > data.int1) {
ctrl.$setValidity('higher', true);
return data.int2;
} else {
ctrl.$setValidity('higher', false);
return undefined;
}
}, true);
Use your own validation variable (int2valid
in your Fiddle) is also very strange. Please use the typical state control, with something like form.int2.$error.higher
.
使用你自己的验证变量(你的小提琴中的int2valid)也很奇怪。请使用典型的状态控件,例如form.int2。$ error.higher。
#2
2
Maybe a simpler solution would be with a watcher or even an expression inside the ng-show direcive of your error span.
也许一个更简单的解决方案可能是观察者甚至是你的错误范围的ng-show方向内的表达。
Using an expression inside the ng-show directive would be like this:
使用ng-show指令中的表达式将是这样的:
<span ng-show="int1 > int2" style="color: red; display:none">
Otherwise you could watch for changes in the models int1 and int2 and compare their values:
否则,您可以观察模型int1和int2中的更改并比较它们的值:
$scope.$watch('int1+int2', function () {
if($scope.int1 > $scope.int2) {
$scope.error = true;
}else {
$scope.error = false;
}
})
<span ng-show="error" style="color: red; display:none">
Here is a fiddle
这是一个小提琴