Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/378.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何覆盖角度';s过滤无效的表单值,强制Angular将$viewValue持久化为$modelValue?_Javascript_Html_Forms_Angularjs_Validation - Fatal编程技术网

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()
然后更新元素的问题

这不是一种非常有棱角的做事方式。如果您需要表单的无效版本,那么我可能会使用指令绑定think
my 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);
            }