Skip nested forms validation with AngularJS
Here is my solution inspired by mbernath, that isolates completely the form itself from its father.
This solution take care of the:
- Form validity ($valid, $invalid)
- Form interaction ($pristine, $dirty)
- Nested forms validity and interaction
See it in action in this 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" :
<form name="parent">
<input type="text" ng-model="outside"/>
<ng-form name="subform" isolate-form>
<input type="text" ng-model="inside"/>
</ng-form>
</form>
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.