【问题标题】:NgModel does not get updated inside NgFor loopNgModel 在 NgFor 循环中没有得到更新
【发布时间】:2020-09-27 09:07:26
【问题描述】:

我正在尝试了解 ngFor 循环中的 ngModel 行为。我创建了简单的 stackblitz 来显示问题:https://stackblitz.com/edit/angular-zaq8zs

当我在第一个输入中输入内容时,我在第二个输入中看到相同的值,并且第二个输入也获得焦点。我知道可以通过添加 trackBy 属性并将其设置为索引而不是身份检查来修复它,但我试图弄清楚为什么会发生这种情况。

如果我理解正确:

  1. 使用 [null,null,null,null] 初始化列表
  2. 我在第一个输入中键入了导致列表更改的内容:['1', null, null, null]。
  3. Angular 然后决定在开头添加一个容器并删除最后一个容器。
  4. 第一个容器现在变成了第二个(这就是焦点在那里的原因)。

但为什么我在第二个输入中看到相同的值?有趣的是:

{{index}} {{list[index]}}

显示有效值,所以我想这与 ngModel 未更新有关。任何想法为什么会发生?

【问题讨论】:

    标签: angular typescript


    【解决方案1】:

    ngFor 中使用list[index] 作为model 是不合逻辑的,在这种情况下,当您尝试编辑输入时,实际上您想直接更改array 而不是model;因此,您将在数组中的对象之间发生冲突,即使您创建像 [1,2][{},{}] 这样的数组也没有什么不同。

    使用let item of ** 的角度逻辑,这意味着let item 来绑定对象:

    <div *ngFor='let item of list'>
          <input [(ngModel)]='item'> {{item}}
    

    有一个但是 (不推荐)

    如果您将数组定义如下,然后在这种情况下为您的模型实现property number,它将适用于您。

    list = [{number: 1}, {number: 2}]
    
    <div *ngFor='let item of list;index as index'>
          <input [(ngModel)]='list[index]["number"]'> {{item | json}}
    

    【讨论】:

      【解决方案2】:

      问题不在于ngModel 没有更新。实际上模型正在完美更新,这里遇到的是*ngFor结构指令优化中更改对象引用的问题

      为了将 DOM 操作减少到最低限度,angulars 的 ngFor 指令进行了高度优化。

      例如,如果将一个元素添加到数组中,它不会重新呈现整个列表。相反,所有现有的 DOM 元素都被重新使用,并且只创建了附加元素。 当从数组中删除一个元素时,也会发生同样的事情。

      此外,当一个元素改变它在数组中的位置时,angular 会注意到这一点,并且只会改变一个 DOM 元素的位置。

      不过,要进行所有这些优化,angular 需要一种方法来识别数组中的每个对象。否则它无法确定发生了什么。默认情况下,它使用对象的引用。

      例如,在使用 REST-API 或使用不可变数据结构时,每个对象的引用一直在变化


      为了防止这种行为,我们可以帮助 angular 通过提供一个所谓的 trackBy 函数来识别每个对象。使用这个函数,我们可以告诉 Angular,哪些属性导致对象是唯一的。

      来源:Angular NgFor: Everything you need to know

      示例

      考虑以下事件顺序

      • 使用 *ngFor 生成的 dom 的当前状态
      <input value='' >
      <input value='1' >
      <input value='' >
      <input value='2' >
      
      • 现在在第一个输入中输入值 5
      <input value='5' >
      <input value='1' >
      <input value='' >
      <input value='2' >
      
      • angular 拥有的信息是输入结构是&lt;input value='' &gt;,因此它将去寻找具有该结构的元素,如果找到第三个元素,则 angular 会更新它。
      <input value='5' >
      <input value='1' >
      <input value='5' >
      <input value='2' >
      

      现在将元素 2 更新为 12,Angular 检查结构为 &lt;input value='1' &gt; 的元素,找到非元素并且什么都不做

      <input value='5' >
      <input value='12' >
      <input value='5' >
      <input value='2' >
      

      【讨论】:

      • 我还是不明白,我的意思是我明白 Angular 使用已经渲染的 DOM 元素,但为什么 {{list[index]}} 部分得到更新而输入中的值没有? (你可以在我的 stackblitz 中查看)。
      猜你喜欢
      • 2021-06-11
      • 2023-03-11
      • 1970-01-01
      • 2018-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-10
      • 2020-11-06
      相关资源
      最近更新 更多