我正在尝试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
有解决方法吗?还是更好的解决方案?
答案 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
});
});
}
};