javascript 使用 AngularJS 跳过嵌套表单验证
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19333544/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Skip nested forms validation with AngularJS
提问by Antelle
How can I skip validation of nested forms with AngularJS? I have to make an outer form valid even when its child form is invalid.
如何使用 AngularJS 跳过嵌套表单的验证?即使其子表单无效,我也必须使外部表单有效。
In the example below outer form should be valid (fOuter.$valid
must be true). By default, it is not. Is there an option?
在下面的示例中,外部形式应该是有效的(fOuter.$valid
必须为真)。默认情况下,它不是。有选择吗?
Code (jsFiddle):
代码(jsFiddle):
<div ng-app ng-controller="Ctrl">
<ng-form name="fOuter">
<h3>Outer form (valid={{fOuter.$valid}})</h3>
<input type="text" name="txtOuter" ng-model="outer" placeholder="(required)" required />
<ng-form name="fInner">
<h3>Inner form (valid={{fInner.$valid}})</h3>
<input type="text" name="txtInner" ng-model="inner" placeholder="(required)" required />
</ng-form>
</ng-form>
</div>
采纳答案by Maxim Shoustin
In Angular forms can be nested. This means that the outer form is valid when all of the child forms are valid as well.
在 Angular 表单中可以嵌套。这意味着当所有子表单也都有效时,外部表单也是有效的。
So there is no way to make outer form to be valid automatically (through $valid
key) when one of inner invalid.
因此,$valid
当内部形式之一无效时,无法使外部形式自动(通过密钥)有效。
Try to use error.required
尝试使用 error.required
<h3>Outer form (valid={{!fOuter.txtOuter.$error.required}})</h3>
Demo Fiddle
演示 Fiddle
From Angular ngForm docs:
来自 Angular ngForm 文档:
The other way should be to use controller, like:
另一种方法应该是使用控制器,例如:
<h3>Outer form (valid={{isOuterFormValid}})</h3>
controller
控制器
$scope.isOuterFormValid = true;
// here, add listener on each input and change flag `isOuterFormValid`
...
回答by 91K00
Here is my solution inspired by mbernath, that isolates completely the form itself from its father.
这是我受 mbernath 启发的解决方案,它将表单本身与其父亲完全隔离。
This solution take care of the:
此解决方案负责:
- Form validity ($valid, $invalid)
- Form interaction ($pristine, $dirty)
- Nested forms validity and interaction
- 表单有效性($valid, $invalid)
- 表单交互($pristine,$dirty)
- 嵌套形式有效性和交互
See it in action in this JSFiddle.
在这个JSFiddle 中查看它的实际效果。
angular.module('isolateForm',[]).directive('isolateForm', [function () {
return {
restrict: 'A',
require: '?form',
link: function (scope, elm, attrs, ctrl) {
if (!ctrl) {
return;
}
// Do a copy of the controller
var ctrlCopy = {};
angular.copy(ctrl, ctrlCopy);
// Get the parent of the form
var parent = elm.parent().controller('form');
// Remove parent link to the controller
parent.$removeControl(ctrl);
// Replace form controller with a "isolated form"
var isolatedFormCtrl = {
$setValidity: function (validationToken, isValid, control) {
ctrlCopy.$setValidity(validationToken, isValid, control);
parent.$setValidity(validationToken, true, ctrl);
},
$setDirty: function () {
elm.removeClass('ng-pristine').addClass('ng-dirty');
ctrl.$dirty = true;
ctrl.$pristine = false;
},
};
angular.extend(ctrl, isolatedFormCtrl);
}
};
}]);
To use it just call the directive "isolate-form" :
要使用它,只需调用指令“isolate-form”:
<form name="parent">
<input type="text" ng-model="outside"/>
<ng-form name="subform" isolate-form>
<input type="text" ng-model="inside"/>
</ng-form>
</form>
回答by mbernath
I faced the same problem. Inside a larger form I needed to have a subform with several controls that shouldn't touch the state of the parent form.
我遇到了同样的问题。在一个较大的表单中,我需要有一个带有多个控件的子表单,这些控件不应触及父表单的状态。
Here's my solution: I wrote a directive "null-form" that removes the subform from the parent form and that does not send any state changes its parent.
这是我的解决方案:我编写了一个指令“null-form”,它从父表单中删除子表单,并且不发送任何状态更改其父表单。
angular.module('nullForm',[]).directive('nullForm', [function () {
return {
restrict: 'A',
require: '?form',
link: function link(scope, element, iAttrs, formController) {
if (! formController) {
return;
}
// Remove this form from parent controller
var parentFormController = element.parent().controller('form');
parentFormController.$removeControl(formController);
// Replace form controller with a "null-controller"
var nullFormCtrl = {
$addControl: angular.noop,
$removeControl: angular.noop,
$setValidity: angular.noop,
$setDirty: angular.noop,
$setPristine: angular.noop
};
angular.extend(formController, nullFormCtrl);
}
};
}]);
You can then use it like this:
然后你可以像这样使用它:
<form name="parent">
<input type="text" ng-model="outside"/>
<ng-form name="subform" null-form>
<input type="text" ng-model="inside"/>
</ng-form>
</form>
Any change or negative validation of "inside" won't take an effect on "parent".
“内部”的任何更改或负面验证都不会对“父”产生影响。
There's one downside, however, due to this solution: subform will not have any state either nor will its CSS classes like ng-invalid etc. work. To accomplish this you would need to re-implement this functionality from the original form-controller.
然而,由于这个解决方案,有一个缺点:子表单不会有任何状态,它的 CSS 类(如 ng-invalid 等)也不会工作。为此,您需要从原始表单控制器重新实现此功能。
回答by Christopher Lenz
At least with Angular 1.5 it seems to be enough to remove the nested form from the parent using $removeControl
:
至少在 Angular 1.5 中,使用$removeControl
以下命令从父级中删除嵌套表单似乎就足够了:
module.directive('isolateForm', function() {
return {
restrict: 'A',
require: '?form',
link: function(scope, element, attrs, formController) {
if (!formController) {
return;
}
var parentForm = formController.$$parentForm; // Note this uses private API
if (!parentForm) {
return;
}
// Remove this form from parent controller
parentForm.$removeControl(formController);
}
};
});
Et voila, pristine and validity states of the parent are no longer affected by the nested form.
瞧,父级的原始状态和有效性状态不再受嵌套形式的影响。
回答by AviG
I found out the solution that worked best was Anton's.
我发现最有效的解决方案是安东的。
Setting the nullFormCtrl suggested by mbernath disables validation on the child form (thxs for paving the way though...).
设置 mbernath 建议的 nullFormCtrl 会禁用对子表单的验证(尽管为此铺平了道路......)。
The only change that I made was in the way the parentForm is accessed. angular does provide a method for that.
我所做的唯一更改是访问 parentForm 的方式。angular 确实为此提供了一种方法。
.directive('isolateForm', [function () {
return {
restrict: 'A',
require: '?form',
link: function link(scope, element, iAttrs, formController) {
if (!formController) {
return;
}
// Remove this form from parent controller
formController.$$parentForm.$removeControl(formController)
var _handler = formController.$setValidity;
formController.$setValidity = function (validationErrorKey, isValid, cntrl) {
_handler(validationErrorKey, isValid, cntrl);
formController.$$parentForm.$setValidity(validationErrorKey, true, this);
}
}
};
}]);
回答by Sugumar
I am a newbie to Angular however, please check whether the below approach helps.
但是,我是 Angular 的新手,请检查以下方法是否有帮助。
<div ng-app ng-controller="Ctrl">
<ng-form name="fOuter">
<h3>Outer form (valid={{fOuter.$valid}})</h3>
<ng-form name="fInner1">
<h3>Inner form 1 (valid={{fInner1.$valid}})</h3>
<input type="text" name="txtInner1" ng-model="outer" placeholder="(required)" required />
</ng-form>
<ng-form name="fInner2">
<h3>Inner form 2 (valid={{fInner2.$valid}})</h3>
<input type="text" name="txtInner2" ng-model="inner" placeholder="(required)" required />
</ng-form>
</ng-form>
</div>
<div ng-app ng-controller="Ctrl">
<ng-form name="fOuter">
<h3>Outer form (valid={{fOuter.$valid}})</h3>
<ng-form name="fInner1">
<h3>Inner form 1 (valid={{fInner1.$valid}})</h3>
<input type="text" name="txtInner1" ng-model="outer" placeholder="(required)" required />
</ng-form>
<ng-form name="fInner2">
<h3>Inner form 2 (valid={{fInner2.$valid}})</h3>
<input type="text" name="txtInner2" ng-model="inner" placeholder="(required)" required />
</ng-form>
</ng-form>
</div>
回答by Yuriy Rozhovetskiy
I had the same issue and resolve it with bit change in local copy of angular.js file itself.
我遇到了同样的问题,并通过在 angular.js 文件本身的本地副本中进行了一些更改来解决它。
Basically, I added new function to the FormController as below:
基本上,我向 FormController 添加了新函数,如下所示:
form.$resetParent = function() {
parentForm = nullFormCtrl;
};
and create custom directive:
并创建自定义指令:
angular.module('myApp').directive('dtIsolatedForm', function () {
return {
restrict: 'A',
require: '?form',
link: function (scope, element, attrs, formController) {
if (!formController || !formController.$parentForm) {
return;
}
formController.$resetParent();
}
};
});
回答by montor
Also inspired by mbernath, I found a simpler solution. It consists of creating a dummy form-like directive only for isolation. The directive stops propagation from nested elements to outer form but it doesn't have any form functionality. You can nest ngForms inside and have them fully functional.
同样受到mbernath 的启发,我找到了一个更简单的解决方案。它包括创建一个仅用于隔离的虚拟形式指令。该指令停止从嵌套元素到外部表单的传播,但它没有任何表单功能。您可以将 ngForms 嵌套在其中并使其功能齐全。
angular.directive('formIsolator', function () {
return {
name: 'form',
restrict: 'EAC',
controller: function() {
this.$addControl = angular.noop;
this.$$renameControl = function(control, name) {
control.$name = name;
};
this.$removeControl = angular.noop;
this.$setValidity = angular.noop;
this.$setDirty = angular.noop;
this.$setPristine = angular.noop;
this.$setSubmitted = angular.noop;
}
};
})
The way is to specify the name of controller in directive definition (name: 'form'
). This property isn't documented, but is used for creating ngForm directive in angular source.
方法是在指令定义(name: 'form'
)中指定控制器的名称。此属性没有记录,但用于在angular source 中创建 ngForm 指令。
回答by Anton
i'd like to suggest mbernath's version without downside
我想建议 mbernath 的版本没有缺点
angular.module('yourModule').directive('isolatedForm', [function () {
return {
restrict: 'A',
require: '?form',
link: function link(scope, element, iAttrs, formController) {
if (!formController) return;
// Remove this form from parent controller
var parentFormController = element.parent().controller('form');
parentFormController.$removeControl(formController);
// override default behavior
var _handler = formController.$setValidity;
formController.$setValidity = function (validationErrorKey, isValid, cntrl) {
_handler(validationErrorKey, isValid, cntrl);
parentFormController.$setValidity(validationErrorKey, true, this);
}
}
};}]);
回答by gr3g
From your controller :
从您的控制器:
Ctrl.isOuterFormValid = function() {
var outerFormIsValid = true;
for(var prop in Ctrl.formName) {
//The form is only inValid if the property is not a new form and it is invalid
if(pvCtrl.pvForm[prop].constructor.name !== "FormController" &&
pvCtrl.pvForm[prop].$invalid){
outerFormIsValid = false;
}
}
alert(outerFormIsValid);
};
FormControlleris an Object that gives you information about your form state.
Adding a form to a form, with ng-form
is adding a FormController
property to your original FormController
Object.
FormController是一个对象,它为您提供有关表单状态的信息。
向表单添加表单,ng-form
即向FormController
原始FormController
对象添加属性。
This has the advantage of not adding a html directive to all your input elements.
这具有不向所有输入元素添加 html 指令的优点。