ngModel 无法正确检测数组更改 [英] ngModel cannot detect array changes correctly

查看:21
本文介绍了ngModel 无法正确检测数组更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

组件模型:

private SomeArray = [{ key: "Initial" }];

用户可以动态添加/删除项目:

addField() {this.SomeArray.push({ key: Math.random().toString() });}removeField(索引:数字){this.SomeArray.splice(index, 1);}

模板标记:

 

<button (click)="addField()" type="button">添加</button>

<div *ngFor="let 字段 SomeArray; let i = index;"><input [(ngModel)]="field.key" #modelField="ngModel" [name]=" 'SomeArray['+i+'].key' " type="text" class="form-control" required/><div [hidden]="modelField.pristine || !(modelField.errors && modelField.errors.required)" class="alert alert-danger">必需的错误

<button (click)="removeField(i)" class="btn btn-danger">Remove</button>

这一直有效,直到用户从 SomeArray 中删除任何项目.如果我最初添加了两个项目:

并删除索引为 1 的那个:

然后在添加另一个项目后,Angular 将其视为项目同时具有 0 和 1 索引(新项目占用"两个输入):

(不显示键为 0.1345... 的项目)

值得注意的是,SomeArray 的项目符合预期,但数据绑定失败.可能是什么原因?

更新:感谢@Stefan Svrkota 和@AJT_82 的评论,我知道这个问题可以通过添加[ngModelOptions]="{standalone: true}" 到所需的输入.但是我无法停止思考问题的原因,没有设置 standalone 选项(每个名称属性都有唯一的值,所以这里没有任何错误).

最后我发现当输入元素仅进入

标签时会发生行为 -

2) Step2 - SomeArray[1].key 已从 controls 集合中移除

3) Step3 - Html 看起来像

4) Step4 我们正在添加一个新项目

所以 formGroup 返回现有项目.

我们如何解决?

1) 不要将我们的控件包裹在 form 标签中

2) 给表单添加ngNoForm属性

3) 使用

[ngModelOptions]="{standalone: true}

以上三种解决方案:

  • 我们可以移除[name]属性绑定

  • 我们不能使用内置的表单组验证

4) 将 trackBy 用于 ngFor

template.html

component.ts

trackByFn(i: number) {返回我;}

Plunker 示例

这样我们的内置表单就可以正常工作

The component model:

private SomeArray = [{ key: "Initial" }];

User can add/remove items dynamically:

addField() {
    this.SomeArray.push({ key: Math.random().toString() });
}

removeField(index: number) {
    this.SomeArray.splice(index, 1);
}

Template markup:

 <div class="col-xs-12">
     <button (click)="addField()" type="button">Add</button>
 </div>

 <div *ngFor="let field of SomeArray; let i = index;">
     <input [(ngModel)]="field.key" #modelField="ngModel" [name]=" 'SomeArray['+i+'].key' " type="text" class="form-control" required />
     <div [hidden]="modelField.pristine || !(modelField.errors && modelField.errors.required)" class="alert alert-danger">
        Required error
     </div>

    <button (click)="removeField(i)" class="btn btn-danger">Remove</button>
 </div>

This works untill user removes any item from SomeArray. If I add some two items initially:

and remove the one with 1 index:

then after adding another item Angular treat it as item has both 0 and 1 index (the new item "occupies" both two inputs):

(item with key 0.1345... is not displayed)

It's worth to noting items of SomeArray are as expected, but data binding fails. What can be the reason of it?

Update: Thanks to the comments of @Stefan Svrkota and @AJT_82 it's known for me the issue can be resolved by adding [ngModelOptions]="{standalone: true}" to the needed input. But I couldn't stop thinking about the reason of the issue in my cause, without setting standalone option (there is unique value for each name attribute so it's excepted nothing wrong here).

Finally I have found that behavior occurs when input elements are into <form> tag only - Plunker sample here (enclosing of template with form tag is the reason that issue).

Any ideas of this behavior?

解决方案

The reason why it happens is ngFor mixes name properties when you delete some item.

When you use ngModel inside form each ngModel control will be added to form controls collection.

Let's see what happens if we have added three items and clicked on Remove the second

1) Step1 - SomeArray[1].key exists in collection controls

2) Step2 - SomeArray[1].key has been removed from controls collection

3) Step3 - Html looks like

4) Step4 We are adding a new item

So formGroup returns existing item.

How we can solve it?

1) Don't wrap our controls in form tag

2) Add ngNoForm attribute to form

<form ngNoForm>

3) Use

[ngModelOptions]="{standalone: true}

With all three solutions above:

  • We can remove [name] property binding

  • We can't use the built in Form group validation

4) Use trackBy for ngFor

template.html

<div *ngFor="let field of SomeArray; let i = index; trackBy: trackByFn">

component.ts

trackByFn(i: number) {
  return i;
}

Plunker Example

This way our built in form will work properly

这篇关于ngModel 无法正确检测数组更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆