Search code examples
javascriptangularjsangularjs-ng-modelangularjs-validation

Dynamic form names and ng-repeat


I need to create several forms on a page based on a dynamic list I get from server. In order to do that I'm trying to use angular ng-repeat like so:

<tr ng-repeat="row in data.rows" ng-show="row.edit" class="edit_row" style="border: 0;">
    <td>
        <div class="col-lg-9">
            <form method="POST" class="form-horizontal" enctype="multipart/form-data" name="{{ row.row_id }}">
                ...
                <input ng-disabled="{{ row.row_id }}.$invalid" value="Save" name="submit" type="submit" ng-click="collection.save_edit(row.row_id);">
            </form>
        </div>
    </td>
</tr>

This doesn't work as expected - form has its name attribute generated properly, but angular is not picking this up. Is there a way to create a form with dynamic name? Or is there a workaround for this issue?

Only idea that comes to my mind is to somehow create FormControllers along with data.rows and use them in ng-repeat but I couldn't find a way to do it either.


Solution

  • You could access form object from the this context of the $scope method, which would represent the child scope anyways. Since it is dynamic form name you pass in the form name and form control will always be attached to the scope with the same name as that of the form. So you could do wither by accessing it on the method or using $scope[row.row_id].$invalid explicitly on the view. Just to be safe i have use ng-attr-name to expand interpolation and set the form name dynamically.

      /*Get form object on save*/
      $scope.save_edit = function(form){
        console.log(this[form]);
      }
    
      /*Returns whether the form is valid or not*/
      $scope.isInvalid = function(form){
        return this[form].$invalid; 
      }
    

    and your form would just be:

    <form novalidate method="POST" class="form-horizontal" enctype="multipart/form-data" 
          ng-attr-name="{{ row.row_id }}">
        <input type="text" name="test" ng-required="true" ng-model="row.test"/>
        <input ng-disabled="isInvalid(row.row_id)" value="Save" name="submit" 
               type="submit" ng-click="save_edit(row.row_id);">
     </form>
    

    Demo

    Side note: In order to be more specific and separate out the form specific functionality you could move these to another controller and set ng-controller at the ng-repeat level, with that you could just use $scope instead of this.