Javascript 如何覆盖角度';s过滤无效的表单值,强制Angular将$viewValue持久化为$modelValue?
我需要能够暂时保存尚未完全验证的数据,然后在准备将其永久化时强制执行验证。但我们正在阻止这一点 我有一张表格。用户可以对表单的早期版本执行Javascript 如何覆盖角度';s过滤无效的表单值,强制Angular将$viewValue持久化为$modelValue?,javascript,html,forms,angularjs,validation,Javascript,Html,Forms,Angularjs,Validation,我需要能够暂时保存尚未完全验证的数据,然后在准备将其永久化时强制执行验证。但我们正在阻止这一点 我有一张表格。用户可以对表单的早期版本执行saveDraft(),这些早期版本将持久保存到服务器。然后,当用户准备就绪时,他们可以submit()表单,表单将使用不同的标志保存表单,从而开始实际处理该数据 我遇到的问题是Angular的内置验证。当用户将某些数据输入到带有验证的输入中时,该数据将缓存在$viewValue属性中。但如果验证失败,它将永远不会复制到$modelValue属性,该属性是对我
saveDraft()
,这些早期版本将持久保存到服务器。然后,当用户准备就绪时,他们可以submit()
表单,表单将使用不同的标志保存表单,从而开始实际处理该数据
我遇到的问题是Angular的内置验证。当用户将某些数据输入到带有验证的输入中时,该数据将缓存在$viewValue
属性中。但如果验证失败,它将永远不会复制到$modelValue
属性,该属性是对我将输入绑定到的实际$scope
属性的引用。因此,“无效”值将不会被持久化
但我们需要坚持下去。我们将在用户提交()时强制用户更正验证失败。此外,我们无法知道用户是否要对视图/控制器的特定实例执行saveDraft()
或submit()
,因此我们无法事先以不同的方式设置视图和验证
我的想法是,我们需要以某种方式迭代表单元素,并以某种方式让数据通过。但我找不到一种灵活且可扩展的方法
我试过设置$scope.formName.inputName.$modelValue=$scope.formName.inputName.$viewValue
,但这似乎让神不安,因为两个值都是空的
我尝试过使用$scope.formName.inputName.$setValidity(“”,true)
,但这只会更新UI状态。它从不触及$modelValue
我可以成功地使用$scope.model.boundPropertyName=$scope.formName.inputName.$viewValue
,但这感觉非常必要,并且不允许boundPropertyName
和inputName
的标识符之间存在任何差异。换句话说,对于所有表单控件,您要么需要单独的函数,要么需要依赖命名约定。它们都是超脆的
所以。。。我如何才能优雅地更新$modelValue
?和/或,是否有另一种更好的方法来获得相同的结果,即有时我可以坚持验证,有时则不进行验证
我正在考虑其他选择,但不满意:
- 仅当用户点击submit()时,手动运行验证。但这破坏了用户界面中即时内联验证的用户体验价值。我们不妨将所有验证工作卸载到服务器上,并每次执行一次往返李>
- 复制ngModel和ngModelController的副本,并对其进行修补以更新
,无论其有效性如何。但当应该有一条更优雅的道路时,这就破坏了框架李>$modelValue
(旁注:Angular似乎在根据验证器在两个方向上过滤数据。如果您在formData.zip的模型上设置了“1234”的默认值,该值不足以进行验证,Angular甚至不会显示它。它从未达到初始值
$viewValue
)我尝试过这样做。基本思想是通过直接从输入元素中抓取文本来更新模型,无论输入是否有效。然后,使用模型数据更新视图$render
,即使视图是未定义的
。我还没有从中获得更改加载时样式的权限,因为数据不正确。我确信这只是用无效的东西调用$setViewValue()
然后更新元素的问题
这不是一种非常有棱角的做事方式。如果您需要表单的无效版本,那么我可能会使用指令绑定thinkmy model no validation=“myDirtyModel.value”
,但这是另一天的任务
这是一把小提琴:
指令的缩写代码:
angular.module('bindApp', []).
controller('bindToViewCtrl', function($scope) {
$scope.zip = /(^\d{5}$)|(^\d{5}-\d{4}$)/;
$scope.formData = {
zip: '1234',
bindToView: true
};
}).
directive('bindToView', function($log) {
return {
require: 'ngModel',
scope: {bindToViewIsOn: '&bindToView', ngModel: '='},
link: function (scope, iElem, iAttr, ngModel) {
if(!ngModel) return;
ngModel.$render = function() {
iElem[0].value = ngModel.$viewValue || ngModel.$modelValue;
};
iElem.on('blur keyup change', function() {
scope.$apply(updateModel);
});
scope.$watch(function() { return scope.bindToViewIsOn(); }, function() {
updateModel();
});
function updateModel(){
if(scope.bindToViewIsOn()){
scope.ngModel = iElem[0].value;
}
}
}
};
});
HTML示例:
<div ng-app="bindApp" ng-controller="bindToViewCtrl">
<form name="bindForm">
<label> Zip Code
<input type="text" ng-pattern="zip" required ng-model="formData.zip" bind-to-view="formData.bindToView" name="zipCode"/>
</label>
<span>$scope.formData.zip: {{formData.zip}}</span>
<br/>
<button ng-click="formData.bindToView = !formData.bindToView">
Bind to View is {{formData.bindToView ? 'On' : 'Off' }}
</button>
</form>
</div>
邮政编码
$scope.formData.zip:{{formData.zip}
绑定到视图的是{{formData.bindToView?'On':'Off'}
埃米尔·范·盖伦(Emil van Galen)有一份报告正好涵盖了这一问题。我使用了他的输入指令,它工作得很好
正如他所指出的,NgModelController的$parsers数组是:
每当控件从DOM读取值时,作为管道执行的函数数组。依次调用每个函数,将值传递给下一个函数。用于清理/转换值以及验证。对于验证,解析器应该使用$setValidity()更新有效性状态,并为无效值返回undefined
因此,要允许将模型更新为无效值,同时保留验证结果,请创建一个指令,该指令不对无效值返回undefined
。例如,Emil指令将无效、未定义的字符串值还原为模型值,否则返回视图值:
angular.module('jdFixInvalidValueFormatting', [])
.directive('input', function() {
return {
require: '?ngModel',
restrict: 'E',
link: function($scope, $element, $attrs, ngModelController) {
var inputType = angular.lowercase($attrs.type);
if (!ngModelController || inputType === 'radio' ||
inputType === 'checkbox') {
return;
}
ngModelController.$formatters.unshift(function(value) {
if (ngModelController.$invalid && angular.isUndefined(value)
&& typeof ngModelController.$modelValue === 'string') {
return ngModelController.$modelValue;
} else {
return value;
}
});
}
};
});
您可以在他的Plunker中看到它的工作原理(还请注意,他改进了对
null
的处理,而不是undefined
):自Angular版本1.3以来,可以使用以下解决方案:
您可以在要保留无效属性的模型的输入字段中设置ng model options=“{allowInvalid:true}”
allowInvalid:表示可以设置模型的布尔值
使用未正确验证的值而不是默认值
将模型设置为“未定义”的行为
然后,当您准备好向用户显示其验证错误时,您可以按照自己的方式进行。只需记住为您的输入和表单提供name
属性,以便您可以引用
if (!self.editForm.$valid && self.editForm.txtCustomer.$invalid) {//workaround to fix typeahead validation issue.
self.editForm.txtCustomer.$setValidity('editable', true);
}