我在Angular中写了一个相当复杂的搜索表单。
表单分为几部分 - 您可以按ID,URL,文本字符串或位置进行搜索。当您同时按文本字符串和位置搜索时,我需要验证您是否一起提交纬度和经度。
换句话说,通过文本字符串搜索很好。通过lat / lng搜索很好。通过文本字符串和纬度搜索但省略经度是不行的。
我尽可能使用HTML5和角度指令来验证各个字段'内容,但是我试图通过使用范围观察器,查看表单对象来验证特定的值组合,并且如果我发现当前搜索模式与特定组合不兼容,则使用$setValidity()
字段。
我目前的问题是,一旦我使用$setValidity()
一次,该验证状态就会被卡住"。当用户切换出'textOrLocation'
搜索模式时,我想让angular回到默认的验证行为。我不明白为什么它没有这样做 - 我在$setValidity()
模式下检查表单后,只调用范围更改'textOrLocation'
。
使用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>
答案 0 :(得分:1)
我的理解是,因为正在观看该功能,所以它实际上是在每次摘要期间由Angular进行评估的。一个简单的解决方案可能是在特定表单不在焦点时将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);
}
}
答案 1 :(得分:1)
要创建复杂的测试,您可以使用小指令use-form-error,这对您将来也可能有用。
使用此指令,您可以写:
<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>
和JS
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;
}
}
});
jsfiddle上的实例:
答案 2 :(得分:0)
我开始工作,您可以在此Plunker
中找到代码有几个问题(我正在假设,你正在尝试在控制器中处理你的表单,而不是在自定义指令中):