1. ホーム
  2. angular

[解決済み] Angular2の変更検出:ネストされたオブジェクトに対してngOnChangesが発生しない

2022-04-23 13:49:11

質問

この件について質問するのは初めてではないのですが、以前の質問で答えが見つかりません。私は、あるコンポーネントに次のようなものを入れています。

<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 をトリガーとして、GoogleMap上のマーカーを再描画します。問題は 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;

解決方法は?

rawLapsData は、たとえ配列の内容を変更したとしても (たとえば項目の追加、削除、項目の変更など)、 同じ配列を指し続けます。

変更検出の際、Angularはコンポーネントの入力プロパティに変更がないかチェックする際、(基本的に)以下のように使用します。 === ダーティチェック用。 配列の場合、これは配列の参照 (のみ) をダーティチェックすることを意味します。 配列の場合は rawLapsData 配列の参照は変更されません。 ngOnChanges() は呼び出されない。

2つの解決策が考えられますね。

  1. 実装する ngDoCheck() を作成し、配列の内容が変更されたかどうかを判断するための独自の変更検出ロジックを実行します。 (Lifecycle Hooks のドキュメントには .)

  2. に新しい配列を代入する。 rawLapsData 配列の内容を変更するたびに 次に ngOnChanges() が呼ばれるのは、配列(の参照)が変更されたように見えるからです。

回答では、別の解決策を考えていましたね。

ここでOPのいくつかのコメントを繰り返す。

私はまだ、どのように laps と同等のものを使っているはずです)。 ngOnChanges() であるのに対し map はできません。

  • laps コンポーネントの各エントリに対して、コード/テンプレートがループします。 lapsData 配列の中身を表示するので、表示されるデータそれぞれにAngularバインディングがあります。
  • Angularがコンポーネントの入力プロパティの変更を検出しない場合でも、( === をチェックします) が、それでも (デフォルトでは) すべてのテンプレートバインディングをダーティにチェックします。これらのいずれかが変更されると、AngularはDOMを更新します。 これがあなたが見ているものです。
  • maps コンポーネントは、おそらくそのテンプレートに lapsData 入力プロパティですよね?そうすると、この違いが説明できますね。

なお lapsData の両コンポーネントと rawLapsData はすべて同じ/1つの配列を指しています。 そのため、Angularが(参照)変更に気づかない場合でも lapsData 入力プロパティは、すべてのコンポーネントがその1つの配列を共有/参照しているため、配列の内容の変更を取得/確認することができます。 プリミティブ型(文字列、数値、ブール値)のように、Angularがこれらの変更を伝搬する必要はありません。 しかし、プリミティブ型では、値を変更すると、常に ngOnChanges() - これは、あなたの回答/解決策で悪用されているものです。

もうお分かりかと思いますが、オブジェクトの入力プロパティは配列の入力プロパティと同じ動作をします。