Angular2更改检测:嵌套对象不触发ngOnChanges [英] Angular2 change detection: ngOnChanges not firing for nested object
问题描述
我知道我不是第一个问这个问题的人,但是我在前面的问题中找不到答案.我把它放在一个组件中
I know I am not the first to ask about this, but I can't find an answer in the previous questions. I have this in one component
<div class="col-sm-5">
<laps
[lapsData]="rawLapsData"
[selectedTps]="selectedTps"
(lapsHandler)="lapsHandler($event)">
</laps>
</div>
<map
[lapsData]="rawLapsData"
class="col-sm-7">
</map>
在控制器中rawLapsdata
有时会发生突变.
In the controller rawLapsdata
gets mutated from time to time.
在laps
中,数据以表格格式作为HTML输出.每当rawLapsdata
更改时,该值就会更改.
In laps
, the data is output as HTML in a tabular format. This changes whenever rawLapsdata
changes.
我的map
组件需要使用ngOnChanges
作为触发来在Google Map上重绘标记.问题在于,当父级中的rawLapsData
更改时,ngOnChanges不会触发.我该怎么办?
My map
component needs to use ngOnChanges
as a trigger to redraw markers on a Google Map. The problem is that ngOnChanges does not fire when rawLapsData
changes in the parent. What can I do?
import {Component, Input, OnInit, OnChanges, SimpleChange} from 'angular2/core';
@Component({
selector: 'map',
templateUrl: './components/edMap/edMap.html',
styleUrls: ['./components/edMap/edMap.css']
})
export class MapCmp implements OnInit, OnChanges {
@Input() lapsData: any;
map: google.maps.Map;
ngOnInit() {
...
}
ngOnChanges(changes: { [propName: string]: SimpleChange }) {
console.log('ngOnChanges = ', changes['lapsData']);
if (this.map) this.drawMarkers();
}
更新:ngOnChanges无法正常工作,但好像lapsData正在更新.在ngInit中是用于缩放更改的事件侦听器,该事件侦听器也调用this.drawmarkers
.当我更改缩放比例时,我确实的确看到了标记的变化.因此,唯一的问题是输入数据更改时我没有收到通知.
Update: ngOnChanges is not working, but it looks as though lapsData is being updated. In the ngInit is an event listener for zoom changes that also calls this.drawmarkers
. When I change the zoom I do indeed see a change in markers. So the only issue is that I don't get the notification at the time the input data changes.
在父母中,我有这行. (请记住,更改反映在圈中,而不反映在地图中.)
In the parent, I have this line. (Recall that the change is reflected in laps, but not in map).
this.rawLapsData = deletePoints(this.rawLapsData, this.selectedTps);
请注意,this.rawLapsData
本身是指向大型json对象中间的指针
And note that this.rawLapsData
is itself a pointer to the middle of a large json object
this.rawLapsData = this.main.data.TrainingCenterDatabase.Activities[0].Activity[0].Lap;
推荐答案
rawLapsData
继续指向同一数组,即使您修改了数组的内容(例如,添加项目,删除项目,更改项目) .
rawLapsData
continues to point to the same array, even if you modify the contents of the array (e.g., add items, remove items, change an item).
在更改检测期间,当Angular检查组件的输入属性是否更改时,它(基本上)使用===
进行脏检查.对于数组,这意味着(仅)对数组引用进行了脏检查.由于rawLapsData
数组引用未更改,因此将不会调用ngOnChanges()
.
During change detection, when Angular checks components' input properties for change, it uses (essentially) ===
for dirty checking. For arrays, this means the array references (only) are dirty checked. Since the rawLapsData
array reference isn't changing, ngOnChanges()
will not be called.
我可以想到两种可能的解决方案:
I can think of two possible solutions:
-
实施
ngDoCheck()
并执行您自己的更改检测逻辑,以确定阵列内容是否已更改. (生命周期挂钩"文档具有示例.)
Implement
ngDoCheck()
and perform your own change detection logic to determine if the array contents have changed. (The Lifecycle Hooks doc has an example.)
将新数组分配给rawLapsData
.然后ngOnChanges()
将被调用,因为数组(引用)将作为更改出现.
Assign a new array to rawLapsData
whenever you make any changes to the array contents. Then ngOnChanges()
will be called because the array (reference) will appear as a change.
在回答中,您想出了另一种解决方案.
In your answer, you came up with another solution.
在OP上重复一些评论:
Repeating some comments here on the OP:
我仍然看不到
laps
如何获取更改(肯定必须使用与ngOnChanges()
本身等效的东西?),而map
无法.
I still don't see how
laps
can pick up on the change (surely it must be using something equivalent tongOnChanges()
itself?) whilemap
can't.
- 在
laps
组件中,您的代码/模板在lapsData
数组中的每个条目上循环,并显示内容,因此所显示的每条数据上都有Angular绑定. - 即使Angular没有检测到对组件输入属性的任何更改(使用
===
检查),它仍然(默认情况下)仍然对所有模板绑定进行脏检查.当这些更改中的任何一个更改时,Angular将更新DOM.这就是您所看到的. -
maps
组件的模板中可能没有与lapsData
输入属性的任何绑定,对吗?那可以解释差异. - In the
laps
component your code/template loops over each entry in thelapsData
array, and displays the contents, so there are Angular bindings on each piece of data that is displayed. - Even when Angular doesn't detect any changes to a component's input properties (using
===
checking), it still (by default) dirty checks all of the template bindings. When any of those change, Angular will update the DOM. That's what you are seeing. - The
maps
component likely doesn't have any bindings in its template to itslapsData
input property, right? That would explain the difference.
请注意,两个组件中的lapsData
和父组件中的rawLapsData
都指向同一/一个数组.因此,即使Angular没有注意到lapsData
输入属性的任何(引用)更改,组件"get"/看到的任何数组内容也会更改,因为它们都共享/引用该数组.我们不需要Angular来传播这些更改,就像我们使用原始类型(字符串,数字,布尔值)一样.但是使用原始类型时,对值的任何更改都将始终触发ngOnChanges()
–这是您在答案/解决方案中利用的东西.
Note that lapsData
in both components and rawLapsData
in the parent component all point to the same/one array. So even though Angular doesn't notice any (reference) changes to the lapsData
input properties, the components "get"/see any array contents changes because they all share/reference that one array. We don't need Angular to propagate these changes, like we would with a primitive type (string, number, boolean). But with a primitive type, any change to the value would always trigger ngOnChanges()
– which is something you exploit in your answer/solution.
您可能已经发现,对象输入属性的行为与数组输入属性相同.
As you probably figured out by now object input properties have the same behavior as array input properties.
这篇关于Angular2更改检测:嵌套对象不触发ngOnChanges的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!