Javascript 在表单级别使用$setValidity后,validity被固定为false
我正在用Angular编写一个相当复杂的搜索表单 表单分为多个部分-您可以按ID、url、文本字符串或位置进行搜索。当您同时按文本字符串和位置进行搜索时,我需要验证您是否同时提交纬度和经度 换句话说,通过文本字符串进行搜索是可以的。通过lat/lng进行搜索是可以的。按文本字符串和纬度搜索,但忽略经度是不正确的 只要有可能,我都会使用HTML5和angular指令来验证各个字段的内容,但我试图通过使用范围观察器、查看表单对象和使用Javascript 在表单级别使用$setValidity后,validity被固定为false,javascript,angularjs,forms,validation,Javascript,Angularjs,Forms,Validation,我正在用Angular编写一个相当复杂的搜索表单 表单分为多个部分-您可以按ID、url、文本字符串或位置进行搜索。当您同时按文本字符串和位置进行搜索时,我需要验证您是否同时提交纬度和经度 换句话说,通过文本字符串进行搜索是可以的。通过lat/lng进行搜索是可以的。按文本字符串和纬度搜索,但忽略经度是不正确的 只要有可能,我都会使用HTML5和angular指令来验证各个字段的内容,但我试图通过使用范围观察器、查看表单对象和使用$setValidity()来验证特定的值组合如果我发现当前搜索模
$setValidity()来验证特定的值组合
如果我发现当前搜索模式与特定字段组合不兼容
我当前的问题是,一旦我使用了$setValidity()
一次,验证状态就会“卡住”。当用户切换出'textOrLocation'
搜索模式时,我想让angular返回其默认的验证行为。我不明白为什么它不这样做-我只在检查表单处于'textOrLocation'
模式后,在范围更改时调用$setValidity()
Javascript:
$scope.search = {
mode: 'id'
};
$scope.$watch(textOrLocationValid, function() {});
function textOrLocationValid() {
var usingTextOrLocation = $scope.search.mode == 'textOrLocation';
if (usingTextOrLocation) {
var textModel = $scope.form.searchText || {},
textValid = textModel.$valid,
textValue = textModel.$modelValue,
latModel = $scope.form.searchLat || {},
latValid = latModel.$valid,
latValue = latModel.$modelValue,
lngModel = $scope.form.searchLng || {},
lngValid = lngModel.$valid,
lngValue = lngModel.$modelValue,
formValid = (textValid && latValid && lngValid) && // No invalid fields
((latValue && 1 || 0) + (lngValue && 1 || 0) != 1) && // Either both lat and long have values, or neither do
(textValue || latValue); // Either text or location are filled out
if (formValid) {
// Explicitly set form validity to true
$scope.form.$setValidity('textOrLocation', true);
} else {
// Explicitly set form validity to false
$scope.form.$setValidity('textOrLocation', false);
}
}
}
HTML
<form name="form">
<div ng-if="search.mode == 'id'">
<input type="text" name="searchId" required>
</div>
<div ng-if="search.mode == 'textOrLocation'">
<input type="text" name="searchText">
<input type="number" name="searchLat" min="-90" max="90" step="0.000001">
<input type="number" name="searchLng" min="-180" max="180" step="0.000001">
</div>
<button ng-disabled="form.$invalid">Submit</button>
</form>
提交
我的理解是,因为函数正在被监视,所以在每个摘要期间,它实际上是通过角度周期性地进行评估的。一个简单的解决方案可能是在特定表单未处于焦点时将textOrLocation的有效性设置为true。这将允许按钮状态取决于id表单中字段的有效性
function textOrLocationValid() {
var usingTextOrLocation = $scope.search.mode == 'textOrLocation';
if (usingTextOrLocation) {
var textModel = $scope.form.searchText || {},
textValid = textModel.$valid,
textValue = textModel.$modelValue,
latModel = $scope.form.searchLat || {},
latValid = latModel.$valid,
latValue = latModel.$modelValue,
lngModel = $scope.form.searchLng || {},
lngValid = lngModel.$valid,
lngValue = lngModel.$modelValue,
formValid = (textValid && latValid && lngValid) && // No invalid fields
((latValue && 1 || 0) + (lngValue && 1 || 0) != 1) && // Either both lat and long have values, or neither do
(textValue || latValue); // Either text or location are filled out
if (formValid) {
// Explicitly set form validity to true
$scope.form.$setValidity('textOrLocation', true);
} else {
// Explicitly set form validity to false
$scope.form.$setValidity('textOrLocation', false);
}
}
else{
// Explicitly set form validity to true because form is not active
$scope.form.$setValidity('textOrLocation', true);
}
}
我让它工作了,你可以在这里找到代码 有几个问题(我假设,您尝试在控制器中处理表单,而不是在自定义指令中):
$scope.form
与视图中的表单不同。表单有自己的作用域。无法在控制器中直接访问。要解决这个问题,我们可以将表单
附加到控制器中声明的$scope.forms
-object(阅读有关继承模式的更多信息)ng model
附加到输入,这样我们就可以$watch它们,因为不可能直接查看表单(请阅读更多)$scope.search
的变化这绝对不是处理自定义验证的最优雅的解决方案。。。我们将尝试为此制定自定义指令。要创建复杂的测试,您可以使用一个小指令,这在将来可能对您有用 使用此指令,您可以编写:
<div ng-form="myForm">
<div>
<input type="text" ng-model="searchText" name="searchText">
<input type="number" ng-model="searchLat" name="searchLat" min="-90" max="90" step="0.000001">
<input type="number" ng-model="searchLng" name="searchLng" min="-180" max="180" step="0.000001">
<span use-form-error="textOrLocation" use-error-expression="textOrLocationValid()" use-error-input="myForm"></span>
</div>
{{myForm.$error}}
<br>
<button ng-disabled="myForm.$invalid">Submit</button>
</div>
}))
现场示例:谢谢!这正是我所缺少的。我不理解“validationErrorKey”(由
$setValidity
获取的第一个参数)的用途。我认为使用表单。$setValidity()
使用true
作为第二个参数将强制窗体的$valid
状态为true。这是不正确的。相反,它将分配给“textOrLocation”错误键的值设置为true,允许所有其他验证指令正常运行。
angular.module('ExampleApp', ['use']).controller('ExampleController', function($scope) {
$scope.search = {
mode: 'textOrLocation'
};
$scope.textOrLocationValid = function() {
var usingTextOrLocation = $scope.search.mode == 'textOrLocation';
if (usingTextOrLocation) {
var textModel = $scope.myForm.searchText || {},
textValid = textModel.$valid,
textValue = textModel.$modelValue,
latModel = $scope.myForm.searchLat || {},
latValid = latModel.$valid,
latValue = latModel.$modelValue,
lngModel = $scope.myForm.searchLng || {},
lngValid = lngModel.$valid,
lngValue = lngModel.$modelValue,
formValid = (textValid && latValid && lngValid) && // No invalid fields
((latValue && 1 || 0) + (lngValue && 1 || 0) != 1) && // Either both lat and long have values, or neither do
(textValue || latValue); // Either text or location are filled out
return !formValid;
} else {
// Explicitly set form validity to true because form is not active
return false;
}
}