我有一个父组件,它使用ajax请求检索对象数组。
此组件有两个子组件:其中一个以树形结构显示对象,另一个以表格格式呈现其内容。父级通过@input属性将数组传递给子级,并且它们正确显示内容。一切都如预期的那样。
更改对象中的某个字段时会出现问题:子组件不会通知这些更改。只有在手动将数组重新分配给其变量时才会触发更改。
我习惯使用Knockout JS,我需要获得类似于observableArrays的效果。
我读过一些关于DoCheck的内容,但我不确定它是如何工作的。
答案 0 :(得分:72)
OnChanges
Lifecycle Hook才会触发。
如果要检查输入数组中的元素是否已添加,移动或删除,可以在DoCheck
生命周期钩子中使用IterableDiffers,如下所示:
constructor(private _iterableDiffers: IterableDiffers) {
this.iterableDiffer = this._iterableDiffers.find([]).create(null);
}
ngDoCheck() {
let changes = this.iterableDiffer.diff(this.inputArray);
if (changes) {
console.log('Changes detected!');
}
}
如果需要检测数组内对象的更改,则需要遍历所有元素,并为每个元素应用KeyValueDiffers。 (您可以与之前的检查同时执行此操作)。
访问此帖子了解详情:Detect changes in objects inside array in Angular2
答案 1 :(得分:6)
您可以使用IterableDiffers
使用它constructor(private _differs: IterableDiffers) {}
ngOnChanges(changes: SimpleChanges): void {
if (!this._differ && value) {
this._differ = this._differs.find(value).create(this.ngForTrackBy);
}
}
ngDoCheck(): void {
if (this._differ) {
const changes = this._differ.diff(this.ngForOf);
if (changes) this._applyChanges(changes);
}
}
答案 2 :(得分:6)
阅读以下文章,不要错过可变对象和不可变对象。
关键问题是你改变了数组元素,而数组引用保持不变。并且Angular2更改检测仅检查数组引用以检测更改。在了解了不可变对象的概念之后,您就会明白为什么会遇到问题以及如何解决它。
我在我的一个项目中使用redux store来避免这类问题。
https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html
答案 3 :(得分:6)
您始终可以通过将其与空数组合并来创建对该数组的新引用:
this.yourArray = [{...}, {...}, {...}];
this.yourArray[0].yourModifiedField = "whatever";
this.yourArray = [].concat(this.yourArray);
上面的代码将更改数组引用,并将触发子组件中的OnChanges机制。
答案 4 :(得分:2)
这已经显示出来了。但是对于将来的问题寻求者,我想补充一些我在研究和调试遇到的变更检测问题时遗漏的东西。现在,我的问题有点孤立,虽然我承认这是一个愚蠢的错误,但仍然有意义。
当您更新参考文献Array
或Object
中的值时,请确保您位于正确的范围内。我使用setInterval(myService.function, 1000)
进入陷阱,其中myService.function()
将更新我在服务之外使用的公共数组的值。由于绑定已关闭,因此它从未真正更新过数组,正确的用法应该是setInterval(myService.function.bind(this), 1000)
。当这是一个愚蠢/简单的错误时,我浪费了时间尝试更改检测黑客。在尝试使用变更检测解决方案之前,应将范围消除为元凶;可能会节省您一些时间。
答案 5 :(得分:1)
这对我有用:
@Component({
selector: 'my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.scss']
})
export class MyComponent implements DoCheck {
@Input() changeArray: MyClassArray[]= [];
private differ: IterableDiffers;
constructor(private differs: IterableDiffers) {
this.differ = differs;
}
ngDoCheck() {
const changes = this.differ.find(this.insertedTasks);
if (changes) {
this.myMethodAfterChange();
}
}
答案 6 :(得分:1)
如果直接在组件模板中使用数组,则可以使用不纯管道。 (此示例适用于不需要深度检查的简单数组)
@Pipe({
name: 'arrayChangeDetector',
pure: false
})
export class ArrayChangeDetectorPipe implements PipeTransform {
private differ: IterableDiffer<any>;
constructor(iDiff: IterableDiffers) {
this.differ = iDiff.find([]).create();
}
transform(value: any[]): any[] {
if (this.differ.diff(value)) {
return [...value];
}
return value;
}
}
<cmp [items]="arrayInput | arrayChangeDetector"></cmp>
对于那些我们当中仍然遇到阵列问题的旅行者,这里是对问题的再现以及几种可能的解决方案。
https://stackblitz.com/edit/array-value-changes-not-detected-ang-8
解决方案包括:
答案 7 :(得分:-2)
LK&#34;我
如果您不介意使用外部库,请使用WatchJS:
https://github.com/melanke/Watch.JS/
import * as WatchJS from 'melanke-watchjs';
var watch = WatchJS.watch;
...
myArray : myObject[] = [];
// on constructor or ngOnInit
watch(this, "myArray", (prop, action, newvalue, oldvalue) => {
// detected change! do stuff here ...
});