Angular ng-repeat with ng-form,在控制器中访问验证 [英] Angular ng-repeat with ng-form, accessing validation in controller
问题描述
我正在尝试使用 ng-repeat
生成可编辑列表.我想提醒用户在继续之前更新任何编辑,所以我使用 ng-form
来动态创建嵌套"表单,因为文档说我可以在这些动态创建的表单上使用验证输入.
虽然这似乎在 HTML 中工作,但我看不到如何访问控制器中那些动态创建的表单和相关的验证字段.具体来说,当用户更改输入时,我使用表单 $dirty 属性来显示一个按钮来告诉用户提交更改.到现在为止还挺好.但是,一旦提交更改,我想在字段上 $setPristine()
以指示已设置更改.可能还有其他方法可以确保在我允许提交主表单之前对每个输入提交更改,但这是我能想到的最好方法.
不幸的是,尽管文档说如果我命名 ng-form 它将被传播到 $scope
对象,但我找不到访问它的方法.$scope.dynamic_form
未定义.
这是一个 plunker 显示我的意思:
谢谢!
只是为了补充这个问题,这个特定示例的工作是添加到动态创建的输入上的 ng-click
:
ng-click="namesForm.name.$setPristine();clean()"
但是我仍然无法访问控制器中动态创建的表单.例如,我想向 namesForm.name.$pristine
添加一个观察者,这样我就可以设置 mainForm.$setValidity(false)
表单是 $dirty
以防止用户在提交所有子表单更改之前提交主表单.
简而言之,问题是如何在父控制器中访问动态创建的嵌套 ngForm 的验证值?
2015-01-17 更新:
正如 Leblanc Meneses 在评论中指出的那样,Angular 1.3 现在支持 form
、ngForm
和 input
的插值> 指令.
这意味着使用表达式来命名您的元素:
<输入类型="文本"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:
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 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.
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屋!