Javascript Angular 2:如何检测数组中的变化?(@input 属性)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42962394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Angular 2: How to detect changes in an array? (@input property)
提问by pablolmedorado
I have a parent component that retrieves an array of objects using an ajax request.
我有一个使用 ajax 请求检索对象数组的父组件。
This component has two children components: One of them shows the objects in a tree structure and the other one renders its content in a table format. The parent passes the array to their children through an @input property and they display the content properly. Everything as expected.
该组件有两个子组件:一个以树结构显示对象,另一个以表格格式呈现其内容。父级通过 @input 属性将数组传递给他们的子级,他们会正确显示内容。一切都如预期。
The problem occurs when you change some field within the objects: the child components are not notified of those changes. Changes are only triggered if you manually reassign the array to its variable.
当您更改对象中的某些字段时会出现问题:子组件不会收到这些更改的通知。仅当您手动将数组重新分配给其变量时才会触发更改。
I'm used to working with Knockout JS and I need to get an effect similar to that of observableArrays.
我习惯使用 Knockout JS,我需要获得类似于 observableArrays 的效果。
I've read something about DoCheck but I'm not sure how it works.
我读过一些关于 DoCheck 的内容,但我不确定它是如何工作的。
回答by Seid Mehmedovic
OnChangesLifecycle Hookwill trigger only when input property's instance changes.
OnChangesLifecycle Hook仅在输入属性的实例更改时触发。
If you want to check whether an element inside the input array has been added, moved or removed, you can use IterableDiffersinside the DoCheckLifecycle Hook as follows:
如果要检查输入数组中的元素是否已添加、移动或删除,可以在Lifecycle Hook 中使用IterableDiffersDoCheck,如下所示:
constructor(private iterableDiffers: IterableDiffers) {
this.iterableDiffer = iterableDiffers.find([]).create(null);
}
ngDoCheck() {
let changes = this.iterableDiffer.diff(this.inputArray);
if (changes) {
console.log('Changes detected!');
}
}
If you need to detect changes in objects inside an array, you will need to iterate through all elements, and apply KeyValueDiffersfor each element. (You can do this in parallel with previous check).
如果需要检测数组内对象的变化,则需要遍历所有元素,并为每个元素应用KeyValueDiffers。(您可以与之前的检查并行执行此操作)。
Visit this post for more information: Detect changes in objects inside array in Angular2
访问这篇文章了解更多信息:在 Angular2 中检测数组内对象的变化
回答by Wojtek Majerski
You can always create a new reference to the array by merging it with an empty array:
您始终可以通过将数组与空数组合并来创建对该数组的新引用:
this.yourArray = [{...}, {...}, {...}];
this.yourArray[0].yourModifiedField = "whatever";
this.yourArray = [].concat(this.yourArray);
The code above will change the array reference and it will trigger the OnChanges mechanism in children components.
上面的代码将更改数组引用,并将触发子组件中的 OnChanges 机制。
回答by Jan Cejka
Read following article, don't miss mutable vs immutable objects.
阅读以下文章,不要错过可变对象和不可变对象。
Key issue is that you mutate array elements, while array reference stays the same. And Angular2 change detection checks only array reference to detect changes. After you understand concept of immutable objects you would understand why you have an issue and how to solve it.
关键问题是你改变了数组元素,而数组引用保持不变。Angular2 更改检测仅检查数组引用以检测更改。在了解了不可变对象的概念后,您就会明白为什么会遇到问题以及如何解决它。
I use redux store in one of my projects to avoid this kind of issues.
我在我的一个项目中使用 redux store 来避免此类问题。
https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html
https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html
回答by Günter Z?chbauer
You can use IterableDiffers
您可以使用IterableDiffers
It's used by *ngFor
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);
}
}
回答by bess
This already appears answered. However for future problem seekers, I wanted to add something missed when I was researching and debugging a change detection problem I had. Now, my issue was a little isolated, and admittedly a stupid mistake on my end, but nonetheless relevant.
When you are updating the values in the Arrayor Objectin reference, ensure that you are in the correct scope. I set myself into a trap by using setInterval(myService.function, 1000), where myService.function()would update the values of a public array, I used outside the service. This never actually updated the array, as the binding was off, and the correct usage should have been setInterval(myService.function.bind(this), 1000). I wasted my time trying change detection hacks, when it was a silly/simple blunder. Eliminate scope as a culprit before trying change detection solutions; it might save you some time.
这似乎已经回答了。然而,对于未来的问题寻求者,我想添加一些在我研究和调试我遇到的变更检测问题时遗漏的东西。现在,我的问题有点孤立,无可否认,这是我的一个愚蠢的错误,但仍然相关。当您更新参考中Array或Object参考中的值时,请确保您处于正确的范围内。我通过使用将自己置于陷阱中setInterval(myService.function, 1000),在那里myService.function()将更新我在服务外部使用的公共数组的值。这实际上从未更新数组,因为绑定已关闭,正确的用法应该是setInterval(myService.function.bind(this), 1000). 我浪费了时间尝试更改检测黑客,当时这是一个愚蠢/简单的错误。在尝试变更检测解决方案之前消除范围作为罪魁祸首;它可能会为您节省一些时间。
回答by Rheimus
You can use an impure pipe if you are directly using the array in your components template. (This example is for simple arrays that don't need deep checking)
如果您直接在组件模板中使用数组,则可以使用不纯的管道。(此示例适用于不需要深度检查的简单数组)
@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>
For those time travelers among us still hitting array problems here is a reproduction of the issue along with several possible solutions.
对于我们中那些仍然遇到数组问题的时间旅行者,这里是问题的再现以及几种可能的解决方案。
https://stackblitz.com/edit/array-value-changes-not-detected-ang-8
https://stackblitz.com/edit/array-value-changes-not-detected-ang-8
Solutions include:
解决方案包括:
回答by Stack Over
It's work for me:
这对我有用:
@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();
}
}

