小编典典

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

all

我知道我不是第一个问这个问题的人,但我在前面的问题中找不到答案。我在一个组件中有这个

<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
地图上的标记。问题是当父级发生更改ngOnChanges时不会触发。rawLapsData我能做些什么?

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正在更新。在
ngOnInit是一个用于缩放更改的事件侦听器,它也调用this.drawmarkers.
当我更改缩放时,我确实看到标记发生了变化。所以唯一的问题是我在输入数据更改时没有收到通知。

在父母中,我有这条线。(回想一下,变化反映在圈数中,但不反映在 中map)。

this.rawLapsData = deletePoints(this.rawLapsData, this.selectedTps);

请注意,this.rawLapsData它本身就是一个指向大型 json 对象中间的指针

this.rawLapsData = this.main.data.TrainingCenterDatabase.Activities[0].Activity[0].Lap;

阅读 56

收藏
2022-08-20

共1个答案

小编典典

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

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

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

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

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

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

在此处重复一些关于 OP 的评论:

我仍然看不到如何laps接受更改(肯定它必须使用与ngOnChanges()自身等效的东西?)而map不能。

  • laps组件中,您的代码/模板循环遍历lapsData数组中的每个条目,并显示内容,因此显示的每条数据都有 Angular 绑定。
  • 即使 Angular 没有检测到组件输入属性的任何更改(使用===检查),它仍然(默认情况下)脏检查所有模板绑定。当其中任何一个发生变化时,Angular 都会更新 DOM。这就是你所看到的。
  • maps组件的模板中可能没有任何绑定到其lapsData输入属性,对吗?这将解释差异。

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

正如您现在可能发现的那样,对象输入属性与数组输入属性具有相同的行为。

2022-08-20