Angular2更改检测:嵌套对象不触发ngOnChanges [英] Angular2 change detection: ngOnChanges not firing for nested object

查看:471
本文介绍了Angular2更改检测:嵌套对象不触发ngOnChanges的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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:

  1. 实施ngDoCheck()并执行您自己的更改检测逻辑,以确定阵列内容是否已更改. (生命周期挂钩"文档具有示例.)

  1. 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 to ngOnChanges() itself?) while map can't.

  • laps组件中,您的代码/模板在lapsData数组中的每个条目上循环,并显示内容,因此所显示的每条数据上都有Angular绑定.
  • 即使Angular没有检测到对组件输入属性的任何更改(使用===检查),它仍然(默认情况下)仍然对所有模板绑定进行脏检查.当这些更改中的任何一个更改时,Angular将更新DOM.这就是您所看到的.
  • maps组件的模板中可能没有与lapsData输入属性的任何绑定,对吗?那可以解释差异.
    • In the laps component your code/template loops over each entry in the lapsData 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 its lapsData 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆