title: AngularJS custom form validation using $http
body: <p>I have a form that looks like this:</p>
  
  <pre><code>&lt;form name="myForm" ng-submit="saveDeployment()"&gt;
      &lt;input type="hidden" value="{{item.CloneUrl}}" name="cloneurl" /&gt;
      &lt;input type="hidden" value="{{Username}}" name="username" /&gt;
  
      &lt;input type="radio" name="deploymenttype" ng-model="item.deploymentType" value="azure" checked="checked"&gt;Azure 
      &lt;br /&gt;
      &lt;input type="radio" name="deploymenttype" ng-model="item.deploymentType" value="ftp"&gt;FTP
  
      &lt;div id="azure" ng-show="item.deploymentType=='azure'"&gt;
          &lt;label for="azurerepo"&gt;Azure Git Repo&lt;/label&gt;
          &lt;input type="text" name="azurerepo" ng-model="item.azurerepo" ng-class="{error: myForm.azurerepo.$invalid}" ng-required="item.deploymentType=='azure'" /&gt;
      &lt;/div&gt;
  
      &lt;div id="ftp" ng-show="item.deploymentType=='ftp'"&gt;
          &lt;label for="ftpserver"&gt;FTP Server&lt;/label&gt;
          &lt;input type="text" name="ftpserver" ng-model="item.ftpserver" ng-class="{error: myForm.ftpserver.$invalid}" ng-required="item.deploymentType=='ftp'"  /&gt;
  
          &lt;label for="ftppath"&gt;FTP Path&lt;/label&gt;
          &lt;input type="text" name="ftppath" ng-model="item.ftppath" ng-class="{error: myForm.ftppath.$invalid}" ng-required="item.deploymentType=='ftp'" /&gt;
  
          &lt;label for="ftpusername"&gt;FTP Username&lt;/label&gt;
          &lt;input type="text" name="ftpusername" ng-model="item.ftpusername" ng-class="{error: myForm.ftpusername.$invalid}" ng-required="item.deploymentType=='ftp'"/&gt;
  
          &lt;label for="ftppassword"&gt;FTP Password&lt;/label&gt;
          &lt;input type="password" name="ftppassword" ng-model="item.ftppassword" ng-class="{error: myForm.ftppassword.$invalid}" ng-required="item.deploymentType=='ftp'"/&gt;
      &lt;/div&gt;
  
      &lt;input type="submit" value="Save" ng-disabled="myForm.$invalid"/&gt;
  
  &lt;/form&gt;
  </code></pre>
  
  <p>Its setup so that the required fields and Save button are all working once data is entered. However, part of my validation will be, <code>"Is the user already registered?"</code> where I will use the data entered to hit the server via POST using $http.</p>
  
  <p>Should I put that logic in the <code>saveDeployment()</code> function or is there a better place to put it?</p>
  
  <p>*<strong><em>UPDATE:</em>*</strong></p>
  
  <p>I've implemented the below which is applied as an attribute on a element but it calls the server/database on every key press which I don't like:</p>
  
  <pre><code> app.directive('repoAvailable', function ($http, $timeout) { // available
          return {
              require: 'ngModel',
              link: function (scope, elem, attr, ctrl) {
                  console.log(ctrl);
                  ctrl.$parsers.push(function (viewValue) {
                      // set it to true here, otherwise it will not 
                      // clear out when previous validators fail.
                      ctrl.$setValidity('repoAvailable', true);
                      if (ctrl.$valid) {
                          // set it to false here, because if we need to check 
                          // the validity of the email, it's invalid until the 
                          // AJAX responds.
                          ctrl.$setValidity('checkingRepo', false);
  
                          // now do your thing, chicken wing.
                          if (viewValue !== "" &amp;&amp; typeof viewValue !== "undefined") {
                              $http.post('http://localhost:12008/alreadyregistered',viewValue) //set to 'Test.json' for it to return true.
                                  .success(function (data, status, headers, config) {
                                      ctrl.$setValidity('repoAvailable', true);
                                      ctrl.$setValidity('checkingRepo', true);
                                  })
                                  .error(function (data, status, headers, config) {
                                      ctrl.$setValidity('repoAvailable', false);
                                      ctrl.$setValidity('checkingRepo', true);
                                  });
                          } else {
                              ctrl.$setValidity('repoAvailable', false);
                              ctrl.$setValidity('checkingRepo', true);
                          }
                      }
                      return viewValue;
                  });
  
              }
          };
      });
  </code></pre>