验证无法使用 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'的主要内容,如果未能解决你的问题,请参考以下文章