title: Angular dynamic required validation of group of fields with field highlight if invalid
body: <p>UPDATE 1: the question will be enhanced based on the feedback from the comments.<br>
  UPDATE 2: Some progress has been made. Need additinoal help to get through. Please read below.<br>
  UPDATE 3: Bug fixing in provided sample code causing duplication in table rows when compiling the element using <code>$compile(el[0])(scope);</code>.</p>
  
  <p>On page load, a list of field names is retrieved from Database which indicates what fields are required using ajax call <code>getRequiredFieldInfo()</code>. This call must be completed successfully before executing the related angular code under the directive <code>check-if-required</code> to manipulate the <code>required</code> attribute. This directive must loop over all input fields and mark them as required based on the list which is retrieved from the Database.</p>
  
  <p>I did some research and found this post which seems to be the closest to my requirements:</p>
  
  <p><a href="https://stackoverflow.com/a/28207652/4180447">https://stackoverflow.com/a/28207652/4180447</a></p>
  
  <p>and finally found a working jsfiddle version here (updated):</p>
  
  <p><a href="http://jsfiddle.net/tarekahf/d50tr99u/" rel="nofollow noreferrer">http://jsfiddle.net/tarekahf/d50tr99u/</a></p>
  
  <p>I can use the following simple approach:</p>
  
  <pre><code>&lt;input name="firstName" type="text" foo ng-required="isFieldRequired('firstName')" /&gt;
  </code></pre>
  
  <p>The function <code>isFieldRequired()</code> will check if the passed field name is found in the list, it will return true.</p>
  
  <p>The problem with this approach is that I have to add this function to each and every field which might be required. </p>
  
  <p>Also, will have to pass the field name each time. To be more efficient, I will have to use a directive on the parent element <code>div</code> or <code>fieldset</code> which will allow me to access all child elements, and process the required attributes for the all the input elements.</p>
  
  <p>This directive need to be changed as follows:</p>
  
  <ul>
  <li><p>To be added to the parent element of the group of fields whose <code>required</code> attribute will be processed and modified if needed.</p></li>
  <li><p>Compare the element name against the list of fields to set as required and apply the change accordingly.</p></li>
  </ul>
  
  <p>The updated code (as I am researching the solution):</p>
  
  <p><strong>STYLE</strong></p>
  
  <pre><code>input.ng-invalid, li.ng-invalid {
      background:#F84072;
      border: 2px red solid;
  }
  </code></pre>
  
  <p><strong>HTML - NAVIGATION TABS:</strong></p>
  
  <pre><code>&lt;ul  class="nav nav-pills"&gt;
      &lt;li ng-class="{'ng-invalid':mainForm.homeForm.$invalid &amp;&amp; mainPromiseResolved}" class="active"&gt;&lt;a data-toggle="pill" href="#home"&gt;&lt;%=homeTabName%&gt;&lt;/a&gt;&lt;/li&gt;
      &lt;li ng-class="{'ng-invalid':mainForm.clientForm.$invalid &amp;&amp; mainPromiseResolved}"&gt;&lt;a data-toggle="pill" href="#menu1"&gt;&lt;%=clientTabName%&gt;&lt;/a&gt;&lt;/li&gt;
      &lt;li ng-class="{'ng-invalid':mainForm.appraiserForm.$invalid &amp;&amp; mainPromiseResolved}"&gt; &lt;a data-toggle="pill" href="#menu2"&gt;&lt;%=appraiserTabName%&gt;&lt;/a&gt;&lt;/li&gt;
      &lt;li ng-class="{'ng-invalid':mainForm.propertyForm.$invalid &amp;&amp; mainPromiseResolved}"&gt;&lt;a data-toggle="pill" href="#menu3"&gt;&lt;%=propertyTabName%&gt;&lt;/a&gt;&lt;/li&gt;
      &lt;li ng-class="{'ng-invalid':mainForm.serviceForm.$invalid &amp;&amp; mainPromiseResolved}"&gt;&lt;a data-toggle="pill" href="#menu4"&gt;&lt;%=servicesTabName%&gt;&lt;/a&gt;&lt;/li&gt;
      &lt;li ng-class="{'ng-invalid':mainForm.constructionStage.$invalid &amp;&amp; mainPromiseResolved}"&gt;&lt;a data-toggle="pill" href="#menu5"&gt;&lt;%=constructionStageTabName%&gt;&lt;/a&gt;&lt;/li&gt;    
      &lt;li ng-class="{'ng-invalid':mainForm.costForm.$invalid &amp;&amp; mainPromiseResolved}"&gt;&lt;a data-toggle="pill" href="#menu6"&gt;&lt;%=costTabName%&gt;&lt;/a&gt;&lt;/li&gt;  
      &lt;li ng-class="{'ng-invalid':mainForm.certificationForm.$invalid &amp;&amp; mainPromiseResolved}" ng-click="redrawCanvas()"&gt;&lt;a data-toggle="pill" href="#menu7"&gt;&lt;%=certificationTabName%&gt;&lt;/a&gt;&lt;/li&gt;
      &lt;li ng-class="{'ng-invalid':mainForm.photosForm.$invalid &amp;&amp; mainPromiseResolved}"&gt;&lt;a data-toggle="pill" href="#menu8"&gt;&lt;%=photoTabName%&gt;&lt;/a&gt;&lt;/li&gt;
      &lt;li ng-class="{'ng-invalid':mainForm.mapForm.$invalid &amp;&amp; mainPromiseResolved}"&gt;&lt;a data-toggle="pill" href="#menu9"&gt;&lt;%=locationTabName%&gt;&lt;/a&gt;&lt;/li&gt;    
  &lt;/ul&gt;
  </code></pre>
  
  <p><strong>HTML - Form</strong></p>
  
  <pre><code>&lt;div id="menu2" class="tab-pane fade" ng-form="appraiserForm"&gt;
      &lt;fieldset ng-disabled="isAppraiserSigned()" check-if-required&gt;
          &lt;input type="text" id="appraiser_name" name="appraiser_name" ng-model="sigRoles.appraiser.roleNameModel" style="width: 536px; "&gt;
          &lt;input type="text" id="appraiser_company" style="width: 536px; "&gt;
          ... 
          ... 
      &lt;/fieldset&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>Javascrip:</strong></p>
  
  <pre><code>app.controller('formMainController', ['$scope', '$timeout', '$q', function($scope, $timeout, $q) {
  
      $scope.runProcessAndInit = function () {
          var q = $q.defer();     //Create a promise controller
          angular.element(document).ready(function(){
              //perform all client updates here
              q.resolve('success');   //notify execution is completed successfully - inside document 'ready' event.
          })
      return q.promise;   //return the promise object.
      }
      //mainPromiseResolved is used to indicate all ajax calls and client updates are done.
      $scope.mainPromiseResolved = false;
      $scope.mainPromise = $scope.runProcessAndInit();
      $scope.mainPromise.then(function(success) {
          //debugger;
          $scope.$broadcast('event:force-model-update');
          //mainPromiseResolved is mainly used in angular validation to prevent showing errors until all client updates are done.
          $scope.mainPromiseResolved = true;
          return 'main promise done';
      })
      $scope.isFieldRequired = function (prmFieldName) {
          var isFound = false;
          var oRequiredField = formView.getRequiredField();
          findField: {
              for(var subformName in oRequiredField) {
                  isFound = prmFieldName in oRequiredField[subformName];
                  if (isFound) {
                      break findField;
                  }
              }
          }
          return isFound;
      }    
      function getRequiredFieldInfo() {
          var q = $q.defer();
          var appUrl = getAppURL();   
          $.get(appUrl + "/servlet/..."
                      + "&amp;timestamp="     + new Date().getTime(), 
                      function(data, status){
              //console.log("json fields:" + data);           
              var obj = JSON.parse(data);
              formView.setRequiredField(obj);
              q.resolve('success');
              // console.log(JSON.stringify(formView.getRequiredField()));            
          });
          return q.promise;
      }
      $scope.requiredFieldsPromise = getRequiredFieldInfo(); 
  }]);
  
  app.directive('checkIfRequired', ['$compile', function ($compile) {
      return {
          require: '?ngModel',
          link: function (scope, el, attrs, ngModel) {
              if (!ngModel) {
                  //return;
              }
              //debugger;
              var children = $(":input", el);
              angular.element(document).ready(function (){
                  scope.requiredFieldsPromise.then(function(success) {
                      //remove the attribute to avoid recursive calls
                      el.removeAttr('check-if-required');
                      //Comment line below as it caused duplication in table raws, and I don't know why.
                      //$compile(el[0])(scope);
                      angular.forEach(children, function(value, key) {
                          //debugger;
                          if (scope.isFieldRequired(value.id)) {
                              angular.element(value).attr('required', true);
                              //el.removeAttr('check-if-required');
                              $compile(value)(scope);
                          }
                      });
                  })
              })
          }
      };
  }]); 
  </code></pre>
  
  <p>I've already made some progress. However, I still need more help. Following is the status:</p>
  
  <ul>
  <li>Done: get required fields list from DB and then execute code in directive to manipulate the <code>required</code> attribute.</li>
  <li><p>Done: Loop over the child input elements from a given angular element <code>el</code> which is passed to link function <code>function (scope, el, attrs, ngModel)</code>. </p></li>
  <li><p>Done: Add <code>required</code> attribute to each child element if <code>isFieldRequired(fieldName)</code> is true?</p></li>
  <li><p>Done: Use promise to ensure all ajax DB calls and client updates are done before executing angular code.</p></li>
  <li><p>How to recursively loop over the child elements if they are nested inside another <code>ng-form</code> subform or <code>div</code> element?</p></li>
  <li><p>How to ensure that each element has ngModel object?</p></li>
  <li><p>How to restrict the directive to <code>div</code>, <code>fieldsset</code> or similar elements?</p></li>
  </ul>
  
  <p>Tarek</p>