Angular ng-repeat with ng-form, accessing validation in controller Angular ng-repeat with ng-form, accessing validation in controller angularjs angularjs

Angular ng-repeat with ng-form, accessing validation in controller


Updated 2015-01-17:

As pointed out by Leblanc Meneses in the comments Angular 1.3 now supports interpolation with form, ngForm and input directives.

This means that using expressions to name your elements:

<div ng-form="namesForm_{{$index}}" ng-repeat="name in names">    <input type="text"           name="input_{{$index}}_0"></input>    <!-- ... --></div>  

will work as expected:

$scope['namesForm_0']$scope.namesForm_1// Access nested form elements:$scope.namesForm_1.input_1_0...

Original answer for Angular <= 1.2:

Working with forms and the ngFormController can get tricky pretty quickly.

You need to be aware that you can dynamically add form elements and inputs but they can't be dynamically named - interpolation does not work in the ngForm or name directives.

For example, if you tried to name your nested forms dynamically like this:

<div ng-form="namesForm_{{$index}}" ng-repeat="name in names">    <!-- ... --></div>  

Instead of making all the nested forms available on the scope like this: scope['namesForm_0'] you would only have access to the single (last) form with the literal name scope['namesForm_{{$index}}'].

In your situation you need to create a custom directive that will be added along with ngFormto handle setting $pristine$ and $invalid for that form instance.

JavaScript:

This directive will watch the $dirty state of its form to set the $validity to prevent submission when dirty and handle setting the $pristine state when the 'clean' button is pressed.

app.directive('formCleaner', function(){    return {        scope: true,        require: '^form',        link: function(scope, element, attr){            scope.clean = function () {                scope.namesForm.$setPristine();            };            scope.$watch('namesForm.$dirty', function(isDirty){                scope.namesForm.$setValidity('name', !isDirty);            });        }    };});

HTML:

Then the only change to your HTML is to add the formCleaner directive.

So change your original HTML from this:

<body ng-controller="MainCtrl">    <form name="mainForm" submit="submit()">        <h3>My Editable List</h3>        <div ng-form="namesForm"             ng-repeat="name in names">            <!-- ... -->        </div>        <button class="btn btn-default" type="submit">Submit</button>    </form></body>

to this, by adding form-cleaner next to ng-form:

<body ng-controller="MainCtrl">    <form name="mainForm" submit="submit()">        <h3>My Editable List</h3>        <!-- Add the `form-cleaner` directive to the element with `ng-form` -->        <div form-cleaner             ng-form="namesForm"             ng-repeat="name in names">            <!-- ... -->        </div>        <button class="btn btn-default" type="submit">Submit</button>    </form></body>

Here is an updated Plunker showing the new behaviour: http://plnkr.co/edit/Lxem5HJXe0UCvslqbJr3?p=preview