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.
In the example below outer form sh
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.
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.
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);
};
FormController is 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.
This has the advantage of not adding a html directive to all your input elements.
I am a newbie to Angular however, please check whether the below approach helps.
<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>
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.
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.
Basically, the objective is to separate the connection between nested forms and perform your own validation / access the $error
objects of the forms independently. This can be did by introducing a modelController in-between two nested forms and allowing that modelController to determine when the parent form controller and the child form controller should be valid / invalid. This can be achieved by increasing the $setValidity()
, which determines when the form should go valid / invalid.
Please find my code in the plunker link below. I have introduced a model controller between the parent and child form. Here I have abstracted the $error
object of child form from the parent form. Meaning, the parent form won't be able to see what is wrong with the child form but it will be invalidated when some field goes invalid in the child form. Only the intermediate modelController knows what fields have issues in the child form. This logic can be tweaked or
extended based on our needs. Please let me know if someone needs more clarification in terms of code.
[plnkr]: https://plnkr.co/edit/5gvctSSqmWiEAUE3YUcZ?p=preview
In Angular forms can be nested. This means that the outer form is valid when all of the child forms are valid as well.
So there is no way to make outer form to be valid automatically (through $valid
key) when one of inner invalid.
Try to use error.required
<h3>Outer form (valid={{!fOuter.txtOuter.$error.required}})</h3>
Demo Fiddle
From Angular ngForm docs:
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`
...