ngModel无法正确检测到数组更改

Mer*_*sov 2 javascript angular2-template angular

组件模型:

private SomeArray = [{ key: "Initial" }];
Run Code Online (Sandbox Code Playgroud)

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

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

removeField(index: number) {
    this.SomeArray.splice(index, 1);
}
Run Code Online (Sandbox Code Playgroud)

模板标记:

 <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>
Run Code Online (Sandbox Code Playgroud)

在用户从中删除任何项目之前,此方法一直有效SomeArray。如果我最初添加了两个项目: 在此处输入图片说明

并删除索引为1的索引:

在此处输入图片说明

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

在此处输入图片说明

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

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

更新:感谢@Stefan Svrkota和@ AJT_82的评论,据我所知,可以通过添加[ngModelOptions]="{standalone: true}"所需的输入来解决问题。但是,如果不设置standalone选项,我就无法停止考虑问题的原因(每个名称属性都有唯一的值,因此这里没有什么错)。

最终,我发现当输入元素仅进入<form>标签时会发生行为- 此处Plunker示例(问题在于带有模板标签的模板的封闭)。

对这种行为有任何想法吗?

yur*_*zui 8

发生这种情况的原因是删除某些项目时ngFor混合name属性。

当您ngModel在内部使用form每个ngModel控件时,都会将其添加到表单控件集合中。

让我们看看如果我们添加了三个项目并单击Remove了第二个项目会发生什么

1)步骤1- SomeArray[1].key存在于集合中controls 在此处输入图片说明

2)步骤2- SomeArray[1].key已从controls收藏夹中删除

在此处输入图片说明

3)Step3-HTML看起来像

在此处输入图片说明

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

在此处输入图片说明

因此formGroup返回现有项目。

我们该如何解决?

1)不要将控件包装在form标记中

2)添加ngNoForm属性到表单

<form ngNoForm>
Run Code Online (Sandbox Code Playgroud)

3)使用

[ngModelOptions]="{standalone: true}
Run Code Online (Sandbox Code Playgroud)

使用以上所有三个解决方案:

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

  • 我们无法使用内置的表单组验证

4) 将trackBy用于ngFor

template.html

<div *ngFor="let field of SomeArray; let i = index; trackBy: trackByFn">
Run Code Online (Sandbox Code Playgroud)

component.ts

trackByFn(i: number) {
  return i;
}
Run Code Online (Sandbox Code Playgroud)

柱塞示例

这样我们的内置表单将正常工作