Monday, March 4, 2013

Angular JS: Validating Form Elements in a Repeater

How do I use Angular's form validation on these dynamically created elements?


The common scenario is this, you have some ng-repeat creating inputs of some sort, and you need to validate them individually. The knee-jerk reaction is to try to dynamically add names to the input like name="test{{$index}}"... but that won't really work. So now what?


ngForm directive!


The ng-form directive allows for nesting forms that can be used for things like partial validation. The idea is simple, on each repeated element, add an ng-form directive with a name. Then inside that, you can now reference inputs by name on that subform.



<!-- The "main" form directive is the outer form tag. -->
<form name="mainForm" ng-submit="submitAll()">
  <ul>        
        <!-- We add ng-form to the tag ng-repeat is on,
               to create a nested form context. -->
 <li ng-repeat="item in items" ng-form="subForm">
   <input type="text" required name="name" ng-model="item.name"/>
          
          <!-- now we can reference the validated field by name -->
          <span ng-show="subForm.name.$error.required">required</span>
          
          <!-- the nested form context itself can also be checked for validity. -->
          <button type="button" ng-disabled="subForm.$invalid" 
                     ng-click="submitOne(item)">Submit One</button>
 </li>
  </ul>

  <!-- last, but not least, the validation from our 
         subform bubbles up to our main form! -->
  <button type="submit" ng-disabled="mainForm.$invalid">Submit All</button>
</form>



So that's the idea in a nutshell. I'm not going to get too much more verbose with it than that. I've already covered form validation and custom validation elsewhere in my blog. But I will leave you with this plunker to play with that demonstrates this sort of dynamically created form validation, so you can fork it and play with it for yourself: