Angular ng-repeat with ng-form,在控制器中访问验证 [英] Angular ng-repeat with ng-form, accessing validation in controller

查看:23
本文介绍了Angular ng-repeat with ng-form,在控制器中访问验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 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 添加一个观察者,这样我就可以设置 mainForm.$setValidity(false)表单是 $dirty 以防止用户在提交所有子表单更改之前提交主表单.

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

解决方案

2015-01-17 更新:

正如 Leblanc Meneses 在评论中指出的那样,Angular 1.3 现在支持 formngForminput 的插值> 指令.

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

<输入类型="文本"name="input_{{$index}}_0"></input><!-- ... -->

将按预期工作:

$scope['namesForm_0']$scope.namesForm_1//访问嵌套的表单元素:$scope.namesForm_1.input_1_0...

<小时>

Angular <= 1.2 的原始答案:

处理表单和 ngFormController 很快就会变得棘手.

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

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

<!-- ... -->

不是像这样在作用域上提供所有嵌套表单:scope['namesForm_0'] 您只能访问具有文字名称 scope 的单个(最后一个)表单['namesForm_{{$index}}'].

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

JavaScript:

该指令将观察其表单的 $dirty 状态以设置 $validity 以防止在脏时提交并处理设置 $pristine 按下清洁"按钮时的状态.

app.directive('formCleaner', function(){返回 {范围:真实,要求:'^形式',链接:功能(范围,元素,属性){scope.clean = 函数 () {scope.namesForm.$setPristine();};scope.$watch('namesForm.$dirty', function(isDirty){scope.namesForm.$setValidity('name', !isDirty);});}};});

HTML:

然后对 HTML 的唯一更改是添加 formCleaner 指令.

因此更改您的原始 HTML:

<form name="mainForm" submit="submit()"><h3>我的可编辑列表</h3><div ng-form="namesForm"ng-repeat="名字中的名字"><!-- ... -->

<button class="btn btn-default" type="submit">Submit</button></表单>

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

<form name="mainForm" submit="submit()"><h3>我的可编辑列表</h3><!-- 将 `form-cleaner` 指令添加到带有 `ng-form` 的元素 --><div 表单清理器ng-form="namesForm"ng-repeat="名字中的名字"><!-- ... -->

<button class="btn btn-default" type="submit">Submit</button></表单>

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

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:

plnk

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

这篇关于Angular ng-repeat with ng-form,在控制器中访问验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆