programing

Angular2 변경 감지: ngOnChanges가 중첩된 개체에 대해 실행되지 않습니다.

instargram 2023. 5. 2. 22:18
반응형

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 요소는 사할구요를 사용해야 .ngOnChangesGoogle 지도에서 마커를 다시 그리는 트리거로 사용할 수 있습니다.는 문는입니다.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는 그 큰입니다.

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

rawLapsData배열의 내용을 수정하더라도(예: 항목 추가, 항목 제거, 항목 변경) 계속해서 동일한 배열을 가리킵니다.

변경 감지 중에 Angular는 구성 요소의 입력 속성에 변경이 있는지 확인할 때 (기본적으로) 를 사용합니다.===부정한 검사 때문에.어레이의 경우 어레이 참조(만)가 더티 체크됨을 의미합니다. rawLapsData, 어이참변지않습다니되경.ngOnChanges()호출되지 않습니다.

저는 두 가지 가능한 해결책을 생각할 수 있습니다.

  1. ngDoCheck()및 고유한 변경 감지 로직을 수행하여 배열 내용이 변경되었는지 확인합니다.(Life Hooks 문서에는 예가 있습니다.

  2. rawLapsData배열 내용을 변경할 때마다 표시됩니다.그리고나서ngOnChanges()배열(참조)이 변경 사항으로 표시되므로 호출됩니다.

당신의 답변에서, 당신은 다른 해결책을 생각해냈습니다.

여기 OP에 대해 몇 가지 의견을 반복하고 있습니다.

도 어떻게 laps변화를 포착할 수 있습니다. (만약 그것이 그것과 동등한 것을 사용해야 한다면)ngOnChanges() 자체로 그자로체)??) 그러는 동안.map못한다.

  • laps/각 코드/코드 합니다.lapsData표시되는 각 데이터 조각에 각도 바인딩이 있을 수 있도록 배열 및 내용을 표시합니다.
  • 속성에 변경을 에도 (Angular 가구 요의 소입 력속 사에 대성한 변사지 감경못 도에하지우하는용항을경성사▁angular▁to(▁even경ties)도못using▁('용▁any에우▁doesn▁angular▁when▁changes▁a하는▁component'▁proper가t▁detects)===확인), 여전히(기본적으로) 모든 템플릿 바인딩을 더티 검사합니다.되면 Angular는DOM을 합니다. Angular는 DOM을 업데이트합니다.그것이 당신이 보고 있는 것입니다.
  • maps 요소의 템플릿에 수 .lapsData속성을 입력하십시오.그것은 그 차이를 설명해 줄 것입니다.

:lapsData와 성구요와 rawLapsData상위 구성 요소에서 모두 동일한/하나의 배열을 가리킵니다.따라서 Angular가 (참조) 변화를 감지하지 못하더라도lapsData입력 속성, 구성 요소는 모두 하나의 배열을 공유/참조하기 때문에 배열 내용 변경사항을 "가져오기"/확인합니다.원시 유형(문자열, 숫자, 부울)을 사용하는 것처럼 이러한 변경 사항을 전파하는 데 Angular가 필요하지 않습니다.하지만 원시 유형의 경우 값을 변경하면 항상 트리거됩니다.ngOnChanges()그것은 당신의 답변/메시지에서 악용하는 것입니다.

지금까지 알 수 있었겠지만 개체 입력 속성은 배열 입력 속성과 동일한 동작을 합니다.

가장 깨끗한 방법은 아니지만 값을 변경할 때마다 개체를 복제할 수 있습니다.

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

나는 당신만의 방식을 구현하는 것보다 이 접근 방식을 더 선호한다고 생각합니다.ngDoCheck()@Gunter Zöchbauer 같은 사람이 차임벨을 울릴 수도 있습니다.

.ts 구성요소)rawLapsData다음과 같이 수행합니다.

rawLapsData = somevalue; // change detection will not happen

솔루션:

rawLapsData = {...somevalue}; //for Object, change detection will happen

rawLapsData = [...somevalue]; //for Array, change detection will happen

그리고.ngOnChanges child component .

Mark Rajcok의 두 번째 솔루션의 확장으로서.

배열 내용을 변경할 때마다 rawLapsData에 새 배열을 할당합니다.어레이(참조)가 변경 사항으로 표시되므로 ngOnChanges()가 호출됩니다.

어레이의 내용을 다음과 같이 복제할 수 있습니다.

rawLapsData = rawLapsData.slice(0);

제가 이것을 언급하는 이유는

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

나한텐 안 통했어요이것이 도움이 되길 바랍니다.

가 외부 ▁up▁data▁the▁if▁need▁다▁statement▁run▁might▁▁library▁to▁data▁the수데이▁external▁from▁an할실터행해가 내에서 data update문을 실행해야 할 수도 있습니다.zone.run(...)zone: NgZoneㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅠzone.run()이미, 그러면 당신은 필요 없을 수도 있습니다.zone.run()

중첩된 개체를 포함하여 개체의 속성을 변경해도 변경 탐지가 트리거되지 않습니다.한 가지 해결책은 'rodash' clone() 함수를 사용하여 새 개체 참조를 재할당하는 것입니다.

import * as _ from 'lodash';

this.foo = _.clone(this.foo);

당신의 문제를 해결할 수 있는 두 가지 해결책이 있습니다.

  1. 사용하다ngDoCheck탐지하기 위해object 이터데경여부변부
  2. 할당object object = Object.create(object)상위 구성 요소에서.

사용하다ChangeDetectorRef.detectChanges()중첩된 개체를 편집할 때 변경 탐지를 실행하도록 Angular에 지시합니다(더티 검사에서 누락됨).

나의 '해킹' 해결책은

   <div class="col-sm-5">
        <laps
            [lapsData]="rawLapsData"
            [selectedTps]="selectedTps"
            (lapsHandler)="lapsHandler($event)">
        </laps>
    </div>
    <map
        [lapsData]="rawLapsData"
        [selectedTps]="selectedTps"   // <--------
        class="col-sm-7">
    </map>

selectTps는 rawLapsData와 동시에 변경되며, 이는 맵이 더 단순한 방법으로 변경 사항을 감지할 수 있는 또 다른 기회를 제공합니다. 목적어 원시 활자우아하지는 않지만 효과가 있습니다.

여기 이 해킹으로 저를 곤경에서 벗어나게 해준 해킹이 있습니다.

OP와 유사한 시나리오 - 데이터를 전달해야 하는 중첩된 Angular 구성 요소가 있지만 입력은 배열을 가리키며, 위에서 언급한 것처럼 Angular는 배열의 내용을 검사하지 않기 때문에 변화를 보지 못합니다.

이를 수정하기 위해 배열을 Angular에 대한 문자열로 변환하여 변경 사항을 감지한 다음 중첩된 구성 요소에서 문자열을 다시 배열로 분할(',')하여 행복한 날들을 다시 표시합니다.

저도 같은 필요성을 우연히 발견했습니다.그리고 저는 이것에 대해 많이 읽었습니다. 그래서, 여기 그 주제에 대한 제 의견이 있습니다.

푸시 시 변경 사항을 감지하려면 내부의 개체 값을 변경할 때 변경 사항을 감지해야 합니다. 그리고 어떻게든 개체를 제거하면 변경 사항을 감지할 수 있습니다.

이미 말했듯이, 변경 감지 전략을 사용합니다.

ChangeDetectionStrategy.onPush를 사용하여 만든 구성 요소가 있다고 가정합니다.

<component [collection]="myCollection"></component>

그런 다음 항목을 누르고 변경 탐지를 트리거합니다.

myCollection.push(anItem);
refresh();

또는 항목을 제거하고 변경 탐지를 트리거할 수 있습니다.

myCollection.splice(0,1);
refresh();

또는 항목의 속성 값을 변경하고 변경 탐지를 트리거할 수 있습니다.

myCollection[5].attribute = 'new value';
refresh();

새로 고침 내용:

refresh() : void {
    this.myCollection = this.myCollection.slice();
}

슬라이스 메서드는 동일한 배열을 반환하고 [= ] 기호는 필요할 때마다 변경 감지를 트리거하여 해당 배열을 새로 참조합니다.쉽고 읽을 수 있는 :)

안부 전해요,

나는 그것을 위해 해킹을 만들어야 했습니다.

I created a Boolean Input variable and toggled it whenever array changed, which triggered change detection in the child component, hence achieving the purpose

깨끗한 솔루션은 아니지만 다음과 같은 방법으로 탐지를 실행할 수 있습니다.

rawLapsData = JSON.parse(JSON.stringify(rawLapsData))

좋아요, 그래서 이것에 대한 저의 해결책은:

this.arrayWeNeed.DoWhatWeNeedWithThisArray();
const tempArray = [...arrayWeNeed];
this.arrayWeNeed = [];
this.arrayWeNeed = tempArray;

그리고 이 트리거 mengOnChanges

였는데, 는 경나의그은것 그 객 가 변 다 였 화 의 우 치 체ngOnChange캡처하지 않았습니다. callapi의 몇됩니다.개체를 다시 초기화하면 문제가 해결되어 문제가 발생했습니다.ngOnChange하위 구성 요소에서 트리거합니다.

비슷한 것

 this.pagingObj = new Paging(); //This line did the magic
 this.pagingObj.pageNumber = response.PageNumber;

다음과 같이 데이터를 조작하는 경우:

this.data.profiles[i].icon.url = '';

그런 다음 을 사용하여 변경 내용을 검색해야 합니다.

let array = this.data.profiles.map(x => Object.assign({}, x)); // It will detect changes

각 ngOn 변경 사항은 배열의 변경 사항을 감지할 수 없기 때문에 객체는 새 참조를 할당해야 합니다.항상 작동합니다!

다음은 ngDoCheck와 함께 IterableDiffer를 사용하는 예입니다.IterableDiffer는 추가/변경/제거된 값에 대해서만 반복 작업을 수행할 수 있기 때문에 시간이 지남에 따라 변경 사항을 추적해야 하는 경우 특히 유용합니다.

IterableDiffer의 장점을 모두 사용하지는 않지만 작동하고 원리를 보여주는 간단한 예는 다음과 같습니다.

export class FeedbackMessagesComponent implements DoCheck {
  @Input()
  messages: UserFeedback[] = [];
  // Example UserFeedback instance { message = 'Ooops', type = Notice }

  @HostBinding('style.display')
  display = 'none';

  private _iterableDiffer: IterableDiffer<UserFeedback>;

  constructor(private _iterableDiffers: IterableDiffers) {
    this._iterableDiffer = this._iterableDiffers.find([]).create(null);
  }

  ngDoCheck(): void {
    const changes = this._iterableDiffer.diff(this.messages);

    if (changes) {
      // Here you can do stuff like changes.forEachRemovedItem()

      // We know contents of this.messages was changed so update visibility:
      this.display = this.messages.length > 0 ? 'block' : 'none';
    }
  }
}

이제 내 메시지에 따라 자동으로 표시/숨기기배열 수:

<app-feedback-messages
  [messages]="myMessagesArray"
></app-feedback-messages>

다음과 같이 중첩된 개체가 있다고 가정합니다.

var obj = {"parent": {"child": {....}}}

완전한 객체의 참조를 통과했다면, 다음과 같습니다.

[wholeObj] = "obj"

이 경우 하위 개체의 변경 내용을 감지할 수 없으므로 이 문제를 해결하기 위해 하위 개체의 참조를 다음과 같은 다른 속성을 통해 전달할 수도 있습니다.

[wholeObj] = "obj" [childObj] = "obj.parent.child"

따라서 하위 개체의 변경 사항도 감지할 수 있습니다.

ngOnChanges(changes: SimpleChanges) { 
    if (changes.childObj) {// your logic here}
}

이벤트에서 개체 또는 배열을 보내기만 하면 됩니다.부모에서 자식으로 문자열이나 숫자를 보내지 마십시오.그건 작동할 것이다.저는 2명의 자녀 구성 요소와 부모님이 있었습니다.this is my Parent.ts : 직접 이벤트 개체를 보냅니다.

dataFrom1To2:any;
dataFrom2To1:any;
  onBallPassEventFrom1(event:any){
    this.dataFrom1To2 = event;
  }

  onBallPassEventFrom2(event:any){
    this.dataFrom2To1 = event;
  }

parent.html은 다음과 같습니다.

<div>I Am The Parent Component!</div>
<div>
    <app-child1 (ballPassEventFrom1)="onBallPassEventFrom1($event)" [datafrom2]="dataFrom2To1"></app-child1>
</div>
<div>
    <app-child2 [datafrom1]="dataFrom1To2" (ballPassEventFrom2)="onBallPassEventFrom2($event)"></app-child2>
</div>

언급URL : https://stackoverflow.com/questions/34796901/angular2-change-detection-ngonchanges-not-firing-for-nested-object

반응형