验证无法正常使用ng-model-options = {updateOn:'提交' }

时间:2016-04-18 03:28:28

标签: angularjs

我正在尝试ng-model-options = {updateOn:'提交'所以我可以坚持模型直到它被提交(这样你就可以取消而不影响模型)。

我遇到的问题是验证只是检查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

  • 如果添加正文,则验证将填写所需的
  • 如果删除主题,则仍会通过所需的验证

有解决方法吗?还是更好的解决方案?

1 个答案:

答案 0 :(得分:1)

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

一种可能的方法是在输入控件上调用公开的$validate方法,例如通过ng-blur。这将在您离开时对控件进行手动验证。如果您查看内置验证的代码,它们实际上是在$viewValue而不是$modelValue进行验证。所以在理论上这应该有效!但是有两个问题。首先,如果$validate$viewValue不同步,$modelValue方法实际上会强制进行模型更新。我认为代码比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
                    });
            });
        }
    };