【问题标题】:Angular ng-repeat with ng-form, accessing validation in controllerAngular ng-repeat 与 ng-form,访问控制器中的验证
【发布时间】:2014-06-03 16:39:29
【问题描述】:

我正在尝试使用ng-repeat 生成可编辑列表。我想提醒用户在继续之前更新任何编辑,所以我使用ng-form 动态创建“嵌套”表单,因为文档说我可以对这些动态创建的输入使用验证。

虽然这似乎在 HTML 中有效,但我看不到如何访问控制器中那些动态创建的表单和相关的验证字段。具体来说,当用户更改输入时,我使用表单 $dirty 属性调出一个按钮来告诉用户提交更改。到现在为止还挺好。但是,一旦提交更改,我想在该字段上$setPristine() 以指示更改已设置。在我允许提交主表单之前,可能还有其他方法可以确保在每个输入上都提交更改,但这是我能想到的最好的方法。

不幸的是,即使文档说如果我将 ng-form 命名为将传播到 $scope 对象,我还是找不到访问它的方法。 $scope.dynamic_form 未定义。

这是一个显示我的意思的 plunker:

plnk

谢谢!

[编辑] 只是为了补充问题,这个特定示例的工作是在动态创建的输入上添加到ng-click

ng-click="namesForm.name.$setPristine();clean()"

但我仍然无法访问控制器中动态创建的表单。例如,我想向namesForm.name.$pristine 添加一个观察者,这样我就可以在子表单为$dirty 时设置mainForm.$setValidity(false) 以防止用户在所有子表单更改完成之前提交主表单已提交。

所以简而言之,问题是如何在父控制器中访问动态创建的嵌套 ngForm 的验证值?

【问题讨论】:

    标签: angularjs validation angularjs-ng-repeat angularjs-ng-form


    【解决方案1】:

    2015 年 1 月 17 日更新:

    正如 Leblanc Meneses 在 cmets Angular 1.3 中指出的那样,现在支持使用 formngForminput 指令进行插值。

    这意味着使用表达式来命名你的元素:

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

    将按预期工作:

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

    Angular

    使用表单和ngFormController 很快就会变得棘手。

    您需要注意,您可以动态添加表单元素和输入,但不能动态命名 - 插值在 ngFormname 指令中不起作用。 p>

    例如,如果您尝试像这样动态命名嵌套表单:

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

    您将只能访问具有文字名称scope['namesForm_{{$index}}'] 的单个(最后一个)表单,而不是像这样在范围内提供所有嵌套表单:scope['namesForm_0']

    在您的情况下,您需要创建一个自定义指令,该指令将与 ngForm 一起添加以处理该表单实例的 $pristine$$invalid 设置。

    JavaScript:

    该指令将监视其表单的$dirty 状态以设置$validity 以防止在脏时提交并在按下“清理”按钮时处理设置$pristine 状态。

    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:

    那么对 HTML 的唯一更改就是添加 formCleaner 指令。

    所以改变你原来的 HTML:

    <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>
    

    为此,在ng-form 旁边添加form-cleaner

    <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>
    

    这是显示新行为的更新 Plunker:http://plnkr.co/edit/Lxem5HJXe0UCvslqbJr3?p=preview

    【讨论】:

    • 今天的插值工作 - 参见源代码:github.com/angular/angular.js/blob/master/src/ng/directive/… - 你可以通过名称获得特定嵌套 ngForm 的 $dirty $invalid 状态。很多可能性。
    • @LeblancMeneses 谢谢你,看起来 Angular 1.3 中添加了插值支持。
    • 谢谢。但是,如果您使用 ngMessages,在 ngForm 和 中支持插值似乎在解决此问题方面价值有限。 ng-messages not 支持插值,因此无法在 ngMessages 元素中引用特定表单 - 它只会引发错误。
    • 动态创建的表单在控制器中不可用。有时仅当在控制器中声明范围变量时才能从视图到控制器。访问时动态创建的变量未定义
    • @JeevaJsb 你必须使用像myforms.namesForm_{{$index}} 这样的名称并在控制器$scope.myforms = {} 中初始化它,这样引用就不会被破坏并且你可以正确使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多