Angular2:* ngFor在更新数组时不更新

时间:2017-07-21 14:03:17

标签: angular angular2-changedetection

我有一个对象数组(让我们称之为arr)。在(change)方法中我的一个组件输入中,我修改了其中一个对象的属性,但在视图中(*ngFor)没有任何变化。我读到Angular2变化检测并没有检查数组或对象的内容,所以我尝试了这些:

this.arr = this.arr.slice();

this.arr = [...this.arr];

但是视图没有改变,它仍然显示旧的属性。在使用(change)的{​​{1}}方法中,我得到了正确的数组。很奇怪,但是这个有效:console.log() 我也尝试了this.arr = [];NgZone

10 个答案:

答案 0 :(得分:3)

尝试通过

创建深层副本
this.arr = Object.assign({}, NEW_VALUE);

答案 1 :(得分:3)

  1. 检查你的组件是否配置了changeDetection:cHangeDetectionStrategy.OnPush,如果你要这样做,那么在更新数组后你必须调用changeDetectorRef.markForCheck()
  2. 您还可以实现onChange生命周期钩子并更改此函数内的数组值。

答案 2 :(得分:3)

您还可以在trackBy表达式中使用*ngFor选项,为数组中的每个项目提供唯一ID。这确实让您100%负责更改检测,因此每次数组中的项更改时都要更新此(唯一)属性。如果数组中的任何项目被赋予不同的trackBy属性,Angular将仅重新呈现列表:

*ngFor="let item of (itemList$ | async); trackBy: trackItem"

或:

*ngFor="let item of itemList; trackBy: trackItem"

其中:

trackItem是您组件中的公共方法:

public trackItem (index: number, item: Item) {
  return item.trackId;
}

答案 3 :(得分:1)

我通过在@component上添加changDetection指令来解决此错误,如下所示:

containerPort

您还需要导入

    @Component({
      selector: 'app-page',
      templateUrl: './page.component.html',
      styleUrls: ['./page.component.scss'],
      changeDetection: ChangeDetectionStrategy.Default
    })

onPush和Default有两种策略

onPush使用CheckOnce策略,这意味着通过将策略设置为Default(CheckAlways)将自动更改检测禁用,直到重新激活。仍然可以显式调用更改检测。

“默认”使用CheckAlways策略,在该策略中,更改检测是自动进行的,直到明确停用为止。

来源Docs

答案 4 :(得分:0)

由于您提到您已经尝试过markForCheck(),因此应该尝试使用detectChanges(这对我和markForCheck都无效)。对于需要这些步骤的人:

将ChangeDetectorRef添加到您的导入中:

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';

将ChangeDetectorRef添加到您的构造函数中:

constructor(
    private changeDetection: ChangeDetectorRef
  ) { }

然后在更新数组后在下一行:

this.changeDetection.detectChanges();

答案 5 :(得分:0)

万一其他人遇到我的情况,请确保要更新的组件与正在渲染的组件是同一副本。

我使用@ViewChild(MyComponent, { static: true }) private test: MyComponent通过ngfor将数据传递到组件。 (在我的情况下,最终锁定了我不知道的另一个副本)

我可以通过将属性#mycomp添加到html中的组件标签并将以上内容更改为@ViewChild('mycomp', { static: true }) private test: MyComponent

来修复它

答案 6 :(得分:0)

游戏后期,但使用lodash创建深层副本对我来说很有效

this.arr = cloneDeep(this.arr);

https://lodash.com/docs/4.17.15#cloneDeep

答案 7 :(得分:0)

不是一个完美的解决方案,但有效:

const temp = this.arr;
this.arr = [];
temp.push(obj); // or any other changes
this.arr = temp;

我真的不喜欢导入新东西,因为会增加包的大小,而且在某些情况下会导致内存问题,所以我是这样处理的。

答案 8 :(得分:0)

如果您重新分配数组,更改检测将不会注意到更改。因此,与其重新分配像 this.arr = ... 这样的数组,不如直接更改数组。这可能看起来像这样:

this.arr.splice(0); // empty the array, without reassigning it
this.arr.push(...); // push new items

这样您就无需手动调用更改检测。

示例

假设有一个可以过滤的表格列表(用户可以即搜索)。因此,我将有一个包含所有可能项目的 list,以及一个在 UI 中使用并显示给用户的 filteredList

// in ngOnInit I load the full list
this.list = this.myService.getList();
this.filteredList = [...this.list] // Since I will change the filtered list directly instead of reassigning it, I need to make a copy to not affect the original full list.

// then in a filter function, i.e. filterList()
this.filteredList.splice(0);
this.filteredList.push([...this.list.filter(/* ... */)]); // Again I need to push copies

答案 9 :(得分:0)

任何时候我需要处理需要更改检测的 *ngFor 我更喜欢使用 behaviorSubject 和异步管道。 (我知道这是一个较长的解决方案。使用行为主题可以轻松地进行更改检测)

array$ = new BehaviorSubject([]);//Declare your array

何时需要更新阵列

array$.next(newArray)://Pass in new array data

如果你想在 .ts 文件中读取你的数组值,请使用这个

array$.getValue()

在您的 .HTML 文件中

*ngFor='let obj of (array$ | async)'