当前位置: 首页 > 知识库问答 >
问题:

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

卜存
2023-03-14

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

<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();
    }

更新:ngOnChanges不工作,但看起来像是正在更新lapsData。在ngInit中是一个用于缩放更改的事件侦听器,它还调用this.drawmarks。当我改变缩放时,我确实看到了标记的变化。所以唯一的问题是我在输入数据更改时没有得到通知。

在父母,我有这一行。(回想一下变化体现在laps上,而不是在map上)。

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

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

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

共有1个答案

越雨泽
2023-03-14

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

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

我能想到两种可能的解决办法:

>

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

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

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

    这里重复一些关于OP的评论:

    我仍然不明白laps如何能够发现更改(肯定是使用了与ngonchanges()本身等价的东西?)而map则不能。

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

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

    现在您可能已经了解到,对象输入属性具有与数组输入属性相同的行为。

  •  类似资料:
    • 还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除: var vm = new Vue({ data: { a: 1 } }) // `vm.a` 现在是响应式的 vm.b = 2 // `vm.b` 不是响应式的 对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用Vue.set(object, key, value)方法向嵌

    • 问题内容: 我需要在ASP .Net应用程序中实现“未保存的更改”提示。如果用户修改了Web表单上的控件,并试图在保存之前导航离开,则将出现提示,警告他们尚未保存更改,并为他们提供取消并保留在当前页面上的选项。如果用户未触摸任何控件,则不应显示该提示。 理想情况下,我想用JavaScript实现此功能,但是在我开始滚动自己的代码之前,是否有任何现有的框架或推荐的设计模式来实现这一目标?理想情况下,

    • 问题内容: 我试图使用makemigrations命令在现有应用程序中创建迁移,但输出“未检测到更改”。 通常,我使用命令创建新应用,但在创建该应用时并未将其用于该应用。 调试后,我发现它没有创建迁移,因为应用程序中缺少软件包/文件夹。 如果不存在该文件夹,还是创建丢失的文件夹,会更好吗? 问题答案: 要为应用创建初始迁移,请运行并指定应用名称。将创建迁移文件夹。 你的应用必须首先包含(在sett

    • 我需要更新嵌套在我的用户文档中的一个字段,该字段包含一个part对象数组,以添加新的part。一个part对象如下所示: 所以这意味着$addToset对我的情况没有好处...现在我不知道该怎么办。