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

前端 未结 1 1206
死守一世寂寞
死守一世寂寞 2020-12-05 04:27

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

相关标签:
1条回答
  • 2020-12-05 04:59

    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

    0 讨论(0)
提交回复
热议问题