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

大憨熊 提交于 2019-11-27 19:19:12

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!