我知道我不是第一个问这个的人,但我在前面的问题中找不到答案 . 我有一个组件
<div class="col-sm-5">
<laps
[lapsData]="rawLapsData"
[selectedTps]="selectedTps"
(lapsHandler)="lapsHandler($event)">
</laps>
</div>
<map
[lapsData]="rawLapsData"
class="col-sm-7">
</map>
在控制器 rawLapsdata
不时变异 .
在 laps
中,数据以表格格式输出为HTML . 只要 rawLapsdata
发生变化,这就会改变 .
我的 map
组件需要使用 ngOnChanges
作为重绘Google Map 上标记的触发器 . 问题是当父级中的 rawLapsData
更改时,ngOnChanges不会触发 . 我能做什么?
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();
}
Update: ngOnChanges无效,但看起来好像正在更新lapsData . 在ngInit中,缩放更改的事件侦听器也调用 this.drawmarkers
. 当我改变变焦时,我确实看到了标记的变化 . 所以唯一的问题是我在输入数据发生变化时没有收到通知 .
在父母,我有这条线 . (回想一下,变化反映在圈数中,但不反映在 Map 中) .
this.rawLapsData = deletePoints(this.rawLapsData, this.selectedTps);
请注意 this.rawLapsData
本身是指向大型json对象中间的指针
this.rawLapsData = this.main.data.TrainingCenterDatabase.Activities[0].Activity[0].Lap;
13 回答
不是最干净的方法,但每次更改值时都可以克隆对象?
我想我更倾向于采用这种方法来实现你自己的
ngDoCheck()
,但也许像@GünterZöchbauer这样的人可以加入 .作为Mark Rajcok第二个解决方案的延伸
您可以像这样克隆数组的内容:
我提到这个是因为
不适合我 . 我希望这有帮助 .
如果数据来自外部库,则可能需要在
zone.run(...)
中运行data upate语句 . 为此注入zone: NgZone
. 如果您已经在zone.run()
中运行外部库的实例化,那么您可能以后不需要zone.run()
.使用
ChangeDetectorRef.detectChanges()
告诉Angular运行更改编辑嵌套对象时检测到它(它错过了脏检查) .rawLapsData
继续指向同一个数组,即使您修改了数组的内容(例如,添加项目,删除项目,更改项目) .在更改检测期间,当Angular检查组件的输入属性以进行更改时,它会(基本上)使用
===
进行脏检查 . 对于数组,这意味着对数组引用(仅)进行脏检查 . 由于rawLapsData
数组引用未更改,因此不会调用ngOnChanges()
.我可以想到两种可能的解决方案:
实现
ngDoCheck()
并执行您自己的更改检测逻辑以确定阵列内容是否已更改 . (Lifecycle Hooks doc有an example . )每当对数组内容进行任何更改时,都会将新数组分配给
rawLapsData
. 然后将调用ngOnChanges()
,因为数组(引用)将显示为更改 .在你的回答中,你提出了另一个解决方案 .
在OP上重复一些评论:
在
laps
组件中,您的代码/模板遍历lapsData
数组中的每个条目,并显示内容,因此在显示的每个数据上都有Angular绑定 .即使Angular没有't detect any changes to a component'的输入属性(使用
===
检查),它仍然(默认情况下)脏检查所有模板绑定 . 当其中任何一个发生变化时,Angular将更新DOM . 这就是你所看到的 .maps
组件可能在其模板中没有任何绑定到其lapsData
输入属性,对吧?这可以解释不同之处 .请注意,两个组件中的
lapsData
和父组件中的rawLapsData
都指向相同/一个数组 . 因此,即使Angular没有注意到lapsData
输入属性的任何(引用)更改,组件"get" /看到任何数组内容都会发生更改,因为它们都共享/引用该数组 . 我们不需要Angular来传播这些更改,就像我们使用基本类型(字符串,数字,布尔值)一样 . 但是对于原始类型,对值的任何更改都将始终触发ngOnChanges()
- 这是您在答案/解决方案中使用的内容 .正如您可能已经想到的那样,对象输入属性与数组输入属性具有相同的行为 .
我的'黑客'解决方案是
selectedTps与rawLapsData同时更改,这使map能够通过更简单的对象基元类型检测更改 . 它不优雅,但它的工作原理 .
在阵列的情况下,您可以这样做:
在
.ts
文件(父组件)中,您要更新rawLapsData
,请执行以下操作:解:
和
ngOnChanges
将在子组件中调用这是一个让我摆脱困境的黑客 .
所以与OP类似的情况 - 我有一个嵌套的Angular组件需要传递给它的数据,但输入指向一个数组,如上所述,Angular没有看到变化,因为它没有检查数组的内容 .
所以要修复它,我将数组转换为Angular的字符串来检测更改,然后在嵌套组件中我将字符串拆分(',')回到数组并再次开心 .
更改对象(包括嵌套对象)的属性时,不会触发更改检测 . 一种解决方案是使用'lodash'clone()函数重新分配新的对象引用 .
我有2个解决方案来解决您的问题
使用
ngDoCheck
检测object
数据是否已更改通过父组件的
object = Object.create(object)
将object
分配给新的内存地址 .我偶然发现了同样的需求 . 我在这方面看了很多,所以这是关于这个主题的铜 .
如果您希望在推送时进行更改检测,那么当您更改对象内部的值时,您会拥有它吗?如果不知何故,你也会删除对象 .
如前所述,使用changeDetectionStrategy.onPush
假设你使用changeDetectionStrategy.onPush创建了这个组件:
然后你推动一个项目并触发变化检测:
或者你删除一个项目并触发更改检测:
或者您更改项目的attrbibute值并触发更改检测:
刷新内容:
slice方法返回完全相同的Array,[=]符号对其进行新的引用,每次需要时触发更改检测 . 简单易读:)
问候,
我已经尝试了这里提到的所有解决方案,但出于某种原因
ngOnChanges()
仍然没有为我开火 . 所以我在调用重新填充我的数组的服务之后用this.ngOnChanges()
调用它并且它工作....正确吗?可能不是 . 整齐?一定不行 . 作品?是!好的,所以我的解决方案是:
这触发了我的变化