I am trying to generate an editable list using ng-repeat
. I want to remind the user to update any edits before moving on, so I am using ng-form
to create "nested" forms on the fly because the documentation says I can then use validation on these dynamically created inputs.
While that seems to work within the HTML, I don't see how to access those dynamically created forms and related validation fields in the controller. Specifically, when the user changes the input I use the form $dirty property to bring up a button to tell the user to commit the changes. So far, so good. However, once the changes are committed I want to $setPristine()
on the field to indicate that the changes have been set. There may be other ways of ensuring that changes are committed on each input before I allow the main form committed, but this was the best I could come up with.
Unfortunately, even though the documentation says that if I name the ng-form it will be propagated to the $scope
object, I can't find a way to access it. $scope.dynamic_form
is undefined.
Here is a plunker showing what I mean:
Thanks!
[EDIT] Just to add to the issue, what does work for this specific example is to add to the ng-click
on the dynamically created input:
ng-click="namesForm.name.$setPristine();clean()"
But I still don't have access to the dynamically created form in the controller. I would like, for example, to add a watcher to the namesForm.name.$pristine
so that I can set the mainForm.$setValidity(false)
whenever the sub-form is $dirty
to prevent the user from submitting the main form until all sub-form changes have been committed.
So in a nutshell, the issue is how to access in a parent controller the validation values of a dynamically created nested ngForm?
Updated 2015-01-17:
As pointed out by Leblanc Meneses in the comments Angular 1.3 now supports interpolation with
form
,ngForm
andinput
directives.This means that using expressions to name your elements:
will work as expected:
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
orname
directives.For example, if you tried to name your nested forms dynamically like this:
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 namescope['namesForm_{{$index}}']
.In your situation you need to create a custom directive that will be added along with
ngForm
to 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.HTML:
Then the only change to your HTML is to add the
formCleaner
directive.So change your original HTML from this:
to this, by adding
form-cleaner
next tong-form
:Here is an updated Plunker showing the new behaviour: http://plnkr.co/edit/Lxem5HJXe0UCvslqbJr3?p=preview