简体   繁体   中英

Angular2: ngDestroy called for component which is ngFor-ed and its reference has changed

I have a small example app here . Several objects ( this.entries in app.component ) are *ngFor-ed and used as input properties for a custom component ( test.component.ts ). When you click the button next to each component its input property is changed to a new object - first the index in the array is retrieved and then the item for that index is set to a new copy (I use such logic because I'm using ChangeDetectionStrategy.OnPush in my other app). When this happens, ngDestroy is called and the component is reinitialized (actually a new component is created).

I already tried trackBy , but nothing changes.

Why is this behaviour and how can I avoid that? What I need is just to use ngOnChanges and not have a whole new component created. While the example here is really simple, I have other situations when similar logic for changing input properties is run more frequently.

i have fixed your example with just trackBy function. perhaps you were doing it wrong. see https://stackblitz.com/edit/angular-vk4mh2?file=src%2Fapp%2Ftest.component.ts

So I put some thought into this. The TrackBy might work in a very specific situation, but I think quite often it wont. If the id changes, you'd get a ngOnDestory and if another field changes, I think the view would ignore it.

I can't think of an elegant solution, but here's a workable one:

HTML:

<test-comp *ngFor="let t of entiresRecords" [prop]="entries[t]" (buttonClick)="onButtonClicked($event)"></test-comp>

TS:

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html'
})
export class AppComponent  {
  entiresRecords;

  entries = [
    { id: 1 },
    { id: 2 },
    { id: 3 }
  ];

  ngOnInit() {
    this.entiresRecords = [];
    for (var i = 0; i < this.entries.length; i++) {
      this.entiresRecords.push(i);
    }
  }

  onButtonClicked (id: number) {
     const targetIndex = this.entries.findIndex(t => t.id === id);
     const copy = Object.assign({}, this.entries[targetIndex], {id: this.entries[targetIndex].id + 3});
     this.entries[targetIndex] = copy;
  }
}

Basically what I've done is created a separate array, for the sole purpose of maintaining the existance of the temp-comp in the dom. This array wouldn't change. I mean, you could write some functionality to add/remove elements if your situation required, but if you are simply reusing the same number of nodes, it wouldn't be necessary to change it.

Now you are free to manipulate the entries array as you please (as long as you maintain the same number of elements)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM