title: AngularJS multi-step form validation
body: <p>I've followed <a href="https://scotch.io/tutorials/angularjs-multi-step-form-using-ui-router" rel="noreferrer">this tutorial</a> about <strong>AngularJS Multi-Step Form Using UI Router</strong>. The form works and I can save my data but now I'm having questions about how to validate each step in the form.</p>
  
  <p>I have the following form with input fields:</p>
  
  <p><strong>Step 1</strong></p>
  
  <blockquote>
    <ul>
    <li>License Plate</li>
    </ul>
  </blockquote>
  
  <p><strong>Step 2</strong></p>
  
  <blockquote>
    <ul>
    <li>Name</li>
    <li>Street</li>
    <li>Zipcode</li>
    <li>City</li>
    <li>Email</li>
    <li>Telephone</li>
    </ul>
  </blockquote>
  
  <p><strong>Step 3</strong></p>
  
  <blockquote>
    <ul>
    <li>Choose a date &amp; time from a calendar</li>
    </ul>
  </blockquote>
  
  <p>It looks somewhat like this:</p>
  
  <p><a href="https://i.stack.imgur.com/c7ie3.png" rel="noreferrer"><img src="https://i.stack.imgur.com/c7ie3.png" alt="enter image description here"></a></p>
  
  <p>I have a general base view like this:</p>
  
  <pre><code>&lt;body ng-app="formApp"&gt;
      &lt;div id="top"&gt;&lt;/div&gt;
      &lt;div class="container"&gt;
          &lt;!-- views will be injected here --&gt;
          &lt;div ui-view&gt;&lt;/div&gt;
  
      &lt;/div&gt;
  &lt;/body&gt;
  </code></pre>
  
  <p>In my app.js I have the following (not complete, left the non important things out):</p>
  
  <pre><code>// app.js
  // create our angular app and inject ngAnimate and ui-router
  // =============================================================================
  angular.module('formApp', ['ngAnimate', 'ui.router', 'ui.calendar'])
  
  // configuring our routes
  // =============================================================================
  .config(function($stateProvider, $urlRouterProvider, $interpolateProvider) {
  
      $interpolateProvider.startSymbol('&lt;%');
      $interpolateProvider.endSymbol('%&gt;');
  
      $stateProvider
  
          // route to show our basic form (/form)
          .state('form', {
              url: '/form',
              templateUrl: 'views/form.html',
              controller: 'formController'
          })
  
          // nested states
          // each of these sections will have their own view
          // url will be /form/interests
          .state('form.license', {
              url: '/license',
              templateUrl: 'views/form-license.html'
          })
  
          // url will be nested (/form/profile)
          .state('form.profile', {
              url: '/profile',
              templateUrl: 'views/form-profile.html'
          })
  
          // url will be /form/payment
          .state('form.appointment', {
              url: '/appointment',
              templateUrl: 'views/form-appointment.html'
          })
  
          // url will be /form/success
          .state('form.success', {
              url: '/success',
              templateUrl: 'views/form-success.html'
          });
  
      // catch all route
      // send users to the form page
      $urlRouterProvider.otherwise('/form/license');
  })
  
  // our controller for the form
  // =============================================================================
  .controller('formController', function($scope, $http, $compile, $location, uiCalendarConfig) {
  
      $scope.formData = {};
      $scope.formData.profile = {};
  
  
      $scope.next = function(step){
  
          if(step == 1) 
          {
  
          }
          else if(step == 2)
          {
  
          }
      };
  
      // function to process the form
      $scope.processForm = function(isValid) {
  
      };
  
  });
  </code></pre>
  
  <p>My general form.html:</p>
  
  <pre><code>&lt;!-- form.html --&gt;
  &lt;div class="row"&gt;
      &lt;div class="col-sm-6 col-sm-offset-3"&gt;
  
          &lt;div id="form-container"&gt;
              &lt;form id="appointment-form" name="appointmentform" ng-submit="processForm(appointmentform.$valid)"&gt;
  
                  &lt;!-- our nested state views will be injected here --&gt;
                  &lt;div id="form-views" ui-view&gt;&lt;/div&gt;
              &lt;/form&gt;
  
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>The first step in my form is in form-license.html:</p>
  
  <pre><code>&lt;!-- form-license.html --&gt;
  &lt;label&gt;Nummerplaat ingeven&lt;/label&gt;
  &lt;div class="form-group"&gt;
      &lt;div class="col-xs-8 col-xs-offset-2"&gt;
          &lt;input required type="text" class="form-control" name="license" ng-model="formData.license"&gt;
  
      &lt;/div&gt;
  &lt;/div&gt;
  
  
  &lt;div class="form-group row"&gt;
      &lt;div class="col-xs-4 col-xs-offset-4"&gt;
          &lt;a ng-click="next(1)" ui-sref="form.profile" class="btn btn-next btn-block"&gt;
              Volgende
          &lt;/a&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>But now I'm wondering how I can validate this when they click on next button ... . It's not working with the normal required attribute.</p>
  
  <p>Can somebody help me with this?</p>
  
  <p><strong>UPDATE:</strong></p>
  
  <p>Now I have in my first step the following:</p>
  
  <pre><code>&lt;div class="col-xs-4 col-xs-offset-4"&gt;
      &lt;a ng-click="next(1, processForm)" ui-sref="form.profile" ng-disabled="!licenseValidated" class="btn btn-next btn-block"&gt;
          Volgende
      &lt;/a&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>In my controller:</p>
  
  <pre><code>var validateLicense = function (newVal) {
      var validated = false;
      // Run your custom validation checks
      if(newVal)
      {
          validated = true;
      }
      return validated;
  };
  
  $scope.$watch('formData.license', function (newVal) {
      $scope.licenseValidated = validateLicense(newVal);
  });
  </code></pre>
  
  <p>Ok, that works. But in my second step I have multiple fields like this:</p>
  
  <pre><code>&lt;div class="profile"&gt;
      &lt;div class="form-group"&gt;
          &lt;label class="col-sm-3 control-label" for="name"&gt;Name&lt;/label&gt;
          &lt;div class="col-sm-9"&gt;
              &lt;input type="text" class="form-control" name="name" ng-model="formData.profile.name"&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div class="form-group"&gt;
          &lt;label class="col-sm-3 control-label" for="street"&gt;Street&lt;/label&gt;
          &lt;div class="col-sm-9"&gt;
              &lt;input type="text" class="form-control" name="street" ng-model="formData.profile.street"&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div class="form-group"&gt;
          &lt;label class="col-sm-3 control-label" for="zipcode"&gt;Zipcode&lt;/label&gt;
          &lt;div class="col-sm-9"&gt;
              &lt;input type="text" class="form-control" name="zipcode" ng-model="formData.profile.zipcode"&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div class="form-group row"&gt;
          &lt;div class="col-xs-8 col-xs-offset-2"&gt;
              &lt;a ng-click="next(1)" ui-sref="form.license" class="btn btn-block btn-previous col-xs-3"&gt;
                  VORIGE
              &lt;/a&gt;
              &lt;a ng-click="next(2)" ui-sref="form.appointment" class="btn btn-block btn-next col-xs-3"&gt;
                  Volgende
              &lt;/a&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>Do I need to create for every one of them a $scope.watch? And do I need to add them to ng-disabled of my button?</p>