验证无法使用 ng-model-options = updateOn: 'submit'

Posted

技术标签:

【中文标题】验证无法使用 ng-model-options = updateOn: \'submit\'【英文标题】:Validation not working properly with ng-model-options = updateOn: 'submit' 验证无法使用 ng-model-options = updateOn: 'submit' 【发布时间】:2016-04-18 03:28:28 【问题描述】:

我正在尝试 ng-model-options = updateOn: 'submit' 以便我可以保留模型直到它被提交(这样你可以取消而不影响模型)。

我遇到的问题是验证只检查 ng-model 而不是表单输入。

有什么方法可以在更新模型之前验证表单?

html

<form name="form" 
        ng-submit="vm.update(vm.action)" 
        ng-model-options=" updateOn: 'submit' " novalidate >

    <label>Subject</label>
    <input name="subject" required ng-model="vm.action.body.subject"/>
    <div ng-messages="form.subject.$error">
        <div ng-message="required">You must enter a subject.</div>
    </div>

    <button ng-click="vm.cancel()">Cancel</button>
    <button type="submit" ng-disabled="form.$invalid">Save</button>
</form>

有关行为的更清晰解释,请参阅 codepen:http://codepen.io/tknz/pen/vGjajo/?editors=1010

如果您添加正文,验证将填写为必填项 如果您删除主题,所需的验证仍将通过

有没有办法解决这个问题?还是更好的解决方案?

【问题讨论】:

如果要实现cancel行为,最好在cancel函数中使用vm.action.body = 我不想清空它,我想保留它的旧值。 好的,最好使用var oldBody = angular.copy(vm.action.body);。然后在cancel 函数vm.action.body = oldBody 中。此解决方案不会破坏验证。 【参考方案1】:

这实际上是一个非常棘手的问题,它使得使用updateOn: submit 来保持一个干净的模型直到提交变得困难。有一些相关的问题。第一个是 updateOn: submit 实际上意味着在提交之前根本不进行验证。在进入表单的过程中会进行初始验证,这是您在表单中移动时唯一可用的验证。因此,如果您的初始表单包含无效字段,您的表单将在您移出某个字段后立即被标记为无效,并且在您提交之前一直如此。

解决此问题的一种可能方法是调用输入控件上公开的$validate 方法,例如通过ng-blur。这将在您离开时对控件进行手动验证。如果您查看内置验证的代码,它们实际上是在 $viewValue 而不是 $modelValue 上进行验证。所以理论上这应该有效!但是有两个问题。首先,如果$viewValue$modelValue 不同步,$validate 方法实际上会强制更新模型。我想该代码比updateOn: submit 的想法更早,他们并没有真正设想让两者不同步的情况是理想的行为。另一个问题更为根本,因为该方法实际上使用了一个名为$$lastCommittedViewValue 的内部值。我不太明白它为什么这样做,而不是仅仅采用实际的$viewValue,但最终结果是在updateOn: submit 情况下$$lastCommittedViewValue 永远不会改变,因为 viewValue 仅在提交时提交.

因此,唯一的官方记录方法是行不通的。然而,查看代码,有一个相当简单的方法,虽然没有记录,但可以解决这个问题。 $validate 方法进行一些初步设置,然后调用内部方法$$runValidators。这通过了 3 个可能的验证器来源,解析器(我认为是一个历史性的工件)以及同步和异步验证器。用真正的$viewValue 直接调用它就足够方便了,而不是最后一个提交的。在表单控制器中设置这样的功能:

        validateNoUpdate(control) 
        control.$$runValidators(control.$modelValue, control.$viewValue,
            function(allValid) 
                console.log("In $$runValidators, allValid : ", allValid);
                // Any post validation code required can be entered here
        );
    

并像这样在输入控件中调用它:

<input id="newClientName" name="newClientName"
   ng-maxlength="5"
   ng-required="true"
   ng-blur="$ctrl.validateNoUpdate(clientForm.newClientName)"
   ng-model-options=" updateOn: 'submit' " ng-model="$ctrl.client.name">

我通常不会考虑使用这样的无证调用,但我真的很讨厌克隆表单对象并在取消时将其复制回来的想法——这似乎充满了潜在的问题。在这种特殊情况下,Angular 1.x 即将结束生命,因此runValidators 被删除或重新使用的可能性较小。另请注意,可以通过直接访问(官方)公开的解析器/syncValidators 和 aSyncValidators 在您的代码中重新创建runValidators。但是代码看起来有点毛茸茸,我很高兴能够使用runValidators 进行更改,直到我将整个代码迁移到 Angular 2。

编辑 - 将其作为指令执行可能会更方便(这是您在 1.5+ 中仍可能在组件上使用指令的少数情况之一),如下所示:

.directive('validateViewOnBlur', function() 
    return 
        require: '?ngModel',
        link: function(scope, element, attrs, ngModel) 
            if (!ngModel) 
                return;
            
            element.on('blur', function() 
                ngModel.$$runValidators(ngModel.$modelValue, ngModel.$viewValue,
                    function(allValid) 
                        console.log("In $$runValidators, allValid : ", allValid);
                        // Any post validation code required can be entered here
                    );
            );
        
    ;

【讨论】:

以上是关于验证无法使用 ng-model-options = updateOn: 'submit'的主要内容,如果未能解决你的问题,请参考以下文章

Angular Material:不显示第二条验证消息

关于ngModelOptions用法总结 让校验不过的验证绑定ngModel

按键操作

Angular 2+ 和去抖动

无法使用 codeigniter 验证码助手创建验证码

输入类型文件无法使用 bootstrapvalidator 进行验证