我有一个对象数组(让我们称之为arr
)。在(change)
方法中我的一个组件输入中,我修改了其中一个对象的属性,但在视图中(*ngFor
)没有任何变化。我读到Angular2变化检测并没有检查数组或对象的内容,所以我尝试了这些:
this.arr = this.arr.slice();
和
this.arr = [...this.arr];
但是视图没有改变,它仍然显示旧的属性。在使用(change)
的{{1}}方法中,我得到了正确的数组。很奇怪,但是这个有效:console.log()
我也尝试了this.arr = [];
和NgZone
。
答案 0 :(得分:3)
尝试通过
创建深层副本this.arr = Object.assign({}, NEW_VALUE);
答案 1 :(得分:3)
答案 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);
答案 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)'