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.