为了账号安全,请及时绑定邮箱和手机立即绑定

Angular2更改检测:ngOnChanges未针对嵌套对象触发

Angular2更改检测:ngOnChanges未针对嵌套对象触发

慕尼黑8549860 2019-08-12 15:53:17
Angular2更改检测:ngOnChanges未针对嵌套对象触发我知道我不是第一个问这个的人,但我在前面的问题中找不到答案。我有一个组件<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地图上重绘标记的触发器。问题是当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();     }更新: ngOnChanges不起作用,但看起来好像正在更新lapsData。在ngInit中,还有一个用于缩放更改的事件侦听器,它也会调用this.drawmarkers。当我改变变焦时,我确实看到了标记的变化。所以唯一的问题是我在输入数据发生变化时没有收到通知。在父母,我有这条线。(回想一下,变化反映在圈数中,但不反映在地图中)。this.rawLapsData = deletePoints(this.rawLapsData, this.selectedTps);请注意,this.rawLapsData它本身是指向大型json对象中间的指针this.rawLapsData = this.main.data.TrainingCenterDatabase.Activities[0].Activity[0].Lap;
查看完整描述

3 回答

?
米琪卡哇伊

TA贡献1998条经验 获得超6个赞

rawLapsData 继续指向同一个数组,即使您修改了数组的内容(例如,添加项目,删除项目,更改项目)。

在更改检测期间,当Angular检查组件的输入属性以进行更改时,它(基本上)===使用脏检查。对于数组,这意味着对数组引用(仅)进行脏检查。由于rawLapsData数组引用没有改变,ngOnChanges()因此不会被调用。

我可以想到两种可能的解决方案:

  1. 实现ngDoCheck()并执行您自己的更改检测逻辑,以确定数组内容是否已更改。(Lifecycle Hooks doc有一个例子。)

  2. rawLapsData每当您对数组内容进行任何更改时,都会分配一个新数组。然后ngOnChanges()将调用因为数组(引用)将显示为更改。

在你的回答中,你提出了另一个解决方案。

在OP上重复一些评论:

我仍然没有看到如何laps能够接受改变(当然它必须使用与ngOnChanges()自身相当的东西?)而map不能。

  • laps组件中,您的代码/模板遍历lapsData数组中的每个条目,并显示内容,因此在显示的每个数据上都有Angular绑定。

  • 即使Angular没有检测到组件输入属性的任何更改(使用===检查),它仍然(默认情况下)脏检查所有模板绑定。当其中任何一个发生变化时,Angular将更新DOM。这就是你所看到的。

  • maps组件可能在其模板中没有任何绑定到其lapsData输入属性,对吧?这可以解释不同之处。

请注意,lapsData在组件和rawLapsData父组件中都指向相同/一个数组。因此,即使Angular没有注意到对lapsData输入属性的任何(引用)更改,组件“get”/看到任何数组内容更改,因为它们共享/引用该一个数组。我们不需要Angular来传播这些更改,就像我们使用基本类型(字符串,数字,布尔值)一样。但是对于原始类型,对值的任何更改都将始终触发ngOnChanges()- 这是您在答案/解决方案中利用的内容。

正如您可能已经想到的那样,对象输入属性与数组输入属性具有相同的行为。


查看完整回答
反对 回复 2019-08-12
?
宝慕林4294392

TA贡献2021条经验 获得超8个赞

不是最干净的方法,但每次更改值时都可以克隆对象?

   rawLapsData = Object.assign({}, rawLapsData);

我想我更喜欢这种方法而不是实现你自己的方法,ngDoCheck()但也许像@GünterZöchbauer这样的人可能会参与其中。


查看完整回答
反对 回复 2019-08-12
?
慕斯王

TA贡献1864条经验 获得超2个赞

作为Mark Rajcok第二个解决方案的延伸

每当对数组内容进行任何更改时,都会为rawLapsData分配一个新数组。然后将调用ngOnChanges(),因为数组(引用)将显示为更改

您可以像这样克隆数组的内容:

rawLapsData = rawLapsData.slice(0);

我提到这个是因为

rawLapsData = Object.assign({},rawLapsData);

不适合我。我希望这有帮助。


查看完整回答
反对 回复 2019-08-12
  • 3 回答
  • 0 关注
  • 1910 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信