title: AngularJS multi-step form validation using ui-router module
body: <p>I have a form that is spread over multiple tabs. Originally, I used the tabset directive from ui-bootstrap, but then came the requirement to deep link to a specific tab, so I thought I'd use nested views from ui-router.</p>
  
  <p>The problem I have is that the parent form is only valid when all the sub-forms are valid, but using ui-router states, only one sub-form is loaded at a time.</p>
  
  <p><a href="http://plnkr.co/edit/4S46gy?p=preview">Here's an example to clarify</a></p>
  
  <p><strong>index.html</strong></p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html ng-app="app"&gt;
  &lt;head&gt;
    &lt;script src="//code.angularjs.org/1.3.0-beta.5/angular.js"&gt;&lt;/script&gt;
    &lt;script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js"&gt;&lt;/script&gt;
    &lt;link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" /&gt;
    &lt;script src="script.js"&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body class="container-fluid"&gt;
    &lt;div ui-view&gt;
      &lt;ul class="list-unstyled"&gt;
        &lt;li&gt;&lt;a ui-sref="edit.basic"&gt;Basic&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a ui-sref="edit.extended"&gt;Extended&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p><strong>script.js</strong></p>
  
  <pre><code>angular.module('app', ['ui.router']).
  config(function($stateProvider) {
    $stateProvider.state('edit', {
      abstract: true,
      url: '/edit/',
      templateUrl: 'edit.html',
      controller: function($scope) {
        $scope.model = {};
      }
    }).
    state('edit.basic', {
      url: '/basic',
      templateUrl: 'basic.html'
    }).
    state('edit.extended', {
      url: '/extended',
      templateUrl: 'extended.html'
    });
  });
  </code></pre>
  
  <p><strong>edit.html</strong></p>
  
  <pre><code>&lt;div class="row" ng-form="editForm"&gt;
    &lt;div class="col-xs-12"&gt;
      &lt;ul class="nav nav-tabs"&gt;
        &lt;li ui-sref-active="active"&gt;
          &lt;a ui-sref="edit.basic"&gt;Basic&lt;/a&gt;
        &lt;/li&gt;
        &lt;li ui-sref-active="active"&gt;
          &lt;a ui-sref="edit.extended"&gt;Extended&lt;/a&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
    &lt;div class="col-xs-12" ui-view&gt;&lt;/div&gt;
    &lt;div class="col-xs-12"&gt;
      &lt;button type="button" class="btn btn-primary" ng-disabled="editForm.$invalid"&gt;Save&lt;/button&gt;
    &lt;/div&gt;
    &lt;div class="col-xs-12"&gt;
      &lt;hr&gt;
      &lt;tt&gt;model = {{model}}&lt;/tt&gt;&lt;br&gt;
      &lt;tt&gt;editForm.$valid = {{editForm.$valid}}&lt;/tt&gt;&lt;br&gt;
      &lt;tt&gt;editForm.basicForm.$valid = {{editForm.basicForm.$valid}}&lt;/tt&gt;&lt;br&gt;
      &lt;tt&gt;editForm.extendedForm.$valid = {{editForm.extendedForm.$valid}}&lt;/tt&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>basic.html</strong></p>
  
  <pre><code>&lt;div ng-form="basicForm"&gt;
    &lt;div class="form-group"&gt;
      &lt;label for="textProperty"&gt;Text Property&lt;/label&gt;
      &lt;input type="text" class="form-control" name="textProperty" id="textProperty" ng-model="model.textProperty" required&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>extended.html</strong></p>
  
  <pre><code>&lt;div ng-form="extendedForm"&gt;
    &lt;div class="form-group"&gt;
      &lt;label for="numericProperty"&gt;Numeric Property&lt;/label&gt;
      &lt;input type="number" class="form-control" name="numericProperty" id="numericProperty" ng-model="model.numericProperty" required&gt;
    &lt;/div&gt;
    &lt;div class="form-group"&gt;
      &lt;label for="dateProperty"&gt;Date Property&lt;/label&gt;
      &lt;input type="date" class="form-control" name="dateProperty" id="dateProperty" ng-model="model.dateProperty" required&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>I am beginning to believe that this approach is not suitable for my purpose. Instead of using nested views, I should continue to use the tabset and use a state parameter to activate the appropriate tab.</p>
  
  <p>I'm interested to know how others would solve it.</p>
  
  <p><strong>UPDATE 1:</strong></p>
  
  <p><a href="http://plnkr.co/edit/jd63Yc?p=preview">Here is one solution I came up with that uses the ui-bootstrap tabset but doesn't use nested ui-router states and instead parameterises the active tab.</a></p>
  
  <p><strong>UPDATE 2:</strong></p>
  
  <p><a href="http://plnkr.co/edit/oxBXj4?p=preview">Here is a solution which uses nested states along with a validator service following the suggestion of Santiago Rebella</a></p>
  
  <p><strong>UPDATE 3:</strong></p>
  
  <p><a href="http://plnkr.co/edit/OyVBpp?p=preview">Here is an alternate solution to update 2 which uses a validator object on the parent state's scope for comparison</a></p>