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
At least with Angular 1.5 it seems to be enough to remove the nested form from the parent using $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.
i'd like to suggest mbernath's version without downside
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);
}
}
};}]);
I had the same issue and resolve it with bit change in local copy of angular.js file itself.
Basically, I added new function to the FormController as below:
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();
}
};
});
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...).
The only change that I made was in the way the parentForm is accessed. angular does provide a method for that.
.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);
}
}
};
}]);
Before you check if the form is valid, simply remove the nestled forms!
vm.parentForm.$removeControl(vm.nestledForm);
Here is my solution inspired by mbernath, that isolates completely the form itself from its father.
This solution take care of the:
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>