AngularJS - Isolated subform validation

Isolated Subform validation

by Jamseer Noordeen

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<div data-ng-app="demoApp" data-ng-controller="nestedFormIsolation" class="main">
  <div class="bg-info wrapper">
    <h4>
			Parent Form
            <span data-ng-if="parentForm.$invalid" class="label label-danger">NG-INVALID</span>
            <span data-ng-if="parentForm.$valid" class="label label-success">NG-VALID</span>
            <span data-ng-if="parentForm.$pristine" class="label label-info">NG-PRISTINE</span>
            <span data-ng-if="parentForm.$dirty" class="label label-warning">NG-DIRTY</span>
		</h4>
    <ng-form name="parentForm">
      <br>
      <input type="text" required data-ng-model="input1" name="input1" />
      <span data-ng-if="parentForm.input1.$invalid" class="label label-danger">NG-INVALID</span>
      <span data-ng-if="parentForm.input1.$valid" class="label label-success">NG-VALID</span>
      <span data-ng-if="parentForm.input1.$pristine" class="label label-info">NG-PRISTINE</span>
      <span data-ng-if="parentForm.input1.$dirty" class="label label-warning">NG-DIRTY</span>
      <br>
      <br>
      <a class="btn btn-default btn-xs" data-ng-click="setPristine(parentForm)">Set pristine</a>
      <div class="indent-block">
        <div class="bg-success wrapper">
          <h4>
						Isolated subform
						<span data-ng-if="isolatedForm.$invalid" class="label label-danger">NG-INVALID</span>
                        <span data-ng-if="isolatedForm.$valid" class="label label-success">NG-VALID</span>
                        <span data-ng-if="isolatedForm.$pristine" class="label label-info">NG-PRISTINE</span>
                        <span data-ng-if="isolatedForm.$dirty" class="label label-warning">NG-DIRTY</span>
					</h4>
          <ng-form name="isolatedForm" data-isolate-form>
            <br>
            <input type="text" required data-ng-model="input2" name="input2" />
            <span data-ng-if="isolatedForm.input2.$invalid"...

CSS

.main {
  margin: 10px;
  font-size: 12px;
}

.wrapper {
  padding: 10px;
  margin-top: 10px;
}

.indent-block {
  padding-left: 30px;
}

.help-block {
  display: inline-block;
}

input.ng-invalid {
  border-color: red;
  border-width: 1px;
}

input.ng-valid {
  border-color: blue;
  border-width: 1px;
}

JavaScript

var demoApp = angular.module('demoApp', []);


demoApp.controller('nestedFormIsolation', function($scope) {
  $scope.setPristine = function(form) {
    form.$setPristine();
  };
});

demoApp.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);
    }
  };
}]);