Angular 2 - NgFor 中与 NgModel 的 2 路绑定

Posted

技术标签:

【中文标题】Angular 2 - NgFor 中与 NgModel 的 2 路绑定【英文标题】:Angular 2 - 2 Way Binding with NgModel in NgFor 【发布时间】:2017-03-11 21:59:01 【问题描述】:

在 Angular 2 中,我如何使用 NgFor 在重复列表中与 NgModel 进行 2 路绑定。以下是我的 plunkr 和代码,但出现错误。

Plunkr

@Component(
  selector: 'my-app',
  template: `
  <div>
    <div *ngFor="let item of toDos;let index = index;">
      <input [(ngModel)]="item" placeholder="item">
    </div>
    Below Should be binded to above input box
    <div *ngFor="let item of toDos">
      <label>item</label>
    </div>
  </div>
  `,
  directives: [MdButton, MdInput]
)
export class AppComponent  
  toDos: string[] =["Todo1","Todo2","Todo3"];
  constructor() 
  ngOnInit() 
  

【问题讨论】:

你得到一个错误,因为你不能这样做:``` `` 你不能绑定 ng-模型到参考变量“项目”。我不确定您要完成什么。你能详细说明一下吗? 没关系,我找到了需要包含 trackByIndex 然后绑定到 toDos [index] 的解决方案。很快就会更新 plunkr。 发布一个答案 :-) 【参考方案1】:

在挖掘之后,我需要在 ngFor 上使用 trackBy。更新了 plnkr 和下面的代码。希望这对其他人有帮助。

Working Plnkr

@Component(
  selector: 'my-app',
  template: `
  <div>
    <div *ngFor="let item of toDos;let index = index;trackBy:trackByIndex;">
      <input [(ngModel)]="toDos[index]" placeholder="item">
    </div>
    Below Should be binded to above input box
    <div *ngFor="let item of toDos">
      <label>item</label>
    </div>
  </div>
  `,
  directives: [MdButton, MdInput]
)
export class AppComponent  
  toDos: string[] =["Todo1","Todo2","Todo3"];
  constructor() 
  ngOnInit() 
  
  trackByIndex(index: number, obj: any): any 
    return index;
  

【讨论】:

实际上trackBy 在您的代码中并不重要!重要的是[(ngModel)]="toDos[index]" 而不是[(ngModel)]="item" @Lars 没有 trackBy 输入失去焦点,似乎挂在我的经验中。 没有 trackBy ngFor 每次更改数组中的字符串时都会重新创建 DOM,因此这是完全必要的。 @Lars trackBy:trackByIndex; 是必需的,否则你会在第一次按键后失去对输入的关注。 如果你的 &lt;input&gt;&lt;form&gt; 中,角度强制你在输入中输入一个名称,在这种情况下,当修改字符串数组时,它会显示 3 次 "Todo3" 但是不会抛出任何错误,其他一切都会正常工作。您可以将名称替换为 [ngModelOptions]="standalone: true",以便在输入中获得所有 3 个不同的字符串。【参考方案2】:

由于两个原因,您所做的事情不起作用。

您必须使用 toDos[index] 而不是带有 ngModel 的项目 (Read for more info) 每个输入都必须有一个唯一的名称

这是解决您问题的有效解决方案。

<div>
<div *ngFor="let item of toDos;let index = index;">
  <input name=aindex [(ngModel)]="toDos[index]" placeholder="item">
</div>
Below Should be binded to above input box
<div *ngFor="let item of toDos">
  <label>item</label>
</div>

【讨论】:

我搜索了多个问题,直到我得到了这个问题的答案。我的问题是“每个输入都必须有一个唯一的名称”。这正是我所需要的! 很高兴我能帮上忙 我也一样 :)。为我节省了大量时间。谢谢老哥 “每个输入都必须有一个唯一的名称” - 这救了我。谢谢大佬 “每个输入都必须有一个唯一的名称”为我修复了它。我的输入值在提交后消失了,但现在它们留在那里,因为每个输入都有不同的名称。非常感谢!【参考方案3】:

试试这个

@Component(
  selector: 'my-app',
  template: `
  <div>
    <div *ngFor="let item of toDos;let index = index;">
  <input [(ngModel)]="item.text" placeholder="item.text">
    </div>
    Below Should be binded to above input box
    <div *ngFor="let item of toDos">
  <label>item.text</label>
    </div>
  </div>
  `,
  directives: [MdButton, MdInput]
   )
export class AppComponent  
  toDos: any[] =[text:"Todo1",text:"Todo2",text:"Todo3"];
  constructor() 
  ngOnInit() 
  

【讨论】:

投反对票的原因如下: 1. 不需要向数组添加密钥。也可以使用字符串数组来完成。所以冗余。 2. "trackBy:trackByIndex;"在这种情况下是必要的,因为如果更改输入,它将更改“toDos”数组的值,这将反过来重新渲染完整的“ngFor”。使用“trackBy:trackByIndex;”不允许重新渲染,因为此代码 ngFor 仅在索引更改时才会重新渲染。 在数组中加一个key表示任何对象都可以在数组中并且可以被这个方法引用,这有助于更多更深入的理解;虽然这里没有使用索引,如下面的 Lasitha Yapa 所示【参考方案4】:

您必须使用 name + index 向 ngModel 添加 name 属性以使其唯一。

<mat-form-field
  #fileNameRef
  appearance="fill"
  color="primary"
  floatLabel="auto"
>
  <input
    matInput
    #fileNameCtrl="ngModel"
    name="originalName index "
    [(ngModel)]="file.originalName"
    type="text"
    autocomplete="off"
    autocapitalize="off"
    readonly
  /> 
</mat-form-field>

【讨论】:

@Tomerikoo 谢谢。我编辑了我的答案。

以上是关于Angular 2 - NgFor 中与 NgModel 的 2 路绑定的主要内容,如果未能解决你的问题,请参考以下文章

从 Angular 2 理解 *ngFor

Angular 2 - NgFor 使用数字而不是集合

在 ngFor 中计数 - Angular 2

在 Angular 2 中打破 NgFor 循环

[Angular 2] *ngFor with index

Angular 2 ngFor 在索引 + 2 处错误地更改值