Winkel: In welchem ​​Lebenszyklus-Hook sind Eingabedaten, die der Komponente zur Verfügung stehen

82

Ich habe eine Komponente, die ein Array von imageObjekten als InputDaten empfängt .

export class ImageGalleryComponent {
  @Input() images: Image[];
  selectedImage: Image;
}

Ich möchte, wenn die Komponente den selectedImageWert lädt , auf das erste Objekt des imagesArrays gesetzt werden. Ich habe versucht, dies im OnInitLebenszyklus-Hook wie folgt zu tun :

export class ImageGalleryComponent implements OnInit {
  @Input() images: Image[];
  selectedImage: Image;
  ngOnInit() {
    this.selectedImage = this.images[0];
  }
}

Dies gibt mir einen Fehler, Cannot read property '0' of undefinedwas bedeutet, dass der imagesWert auf dieser Stufe nicht eingestellt ist. Ich habe auch den OnChangesHook ausprobiert , stecke aber fest, weil ich keine Informationen darüber erhalten kann, wie Änderungen eines Arrays beobachtet werden können. Wie kann ich das erwartete Ergebnis erzielen?

Die übergeordnete Komponente sieht folgendermaßen aus:

@Component({
  selector: 'profile-detail',
  templateUrl: '...',
  styleUrls: [...],
  directives: [ImageGalleryComponent]
})

export class ProfileDetailComponent implements OnInit {
  profile: Profile;
  errorMessage: string;
  images: Image[];
  constructor(private profileService: ProfileService, private   routeParams: RouteParams){}

  ngOnInit() {
    this.getProfile();
  }

  getProfile() {
    let profileId = this.routeParams.get('id');
    this.profileService.getProfile(profileId).subscribe(
    profile => {
     this.profile = profile;
     this.images = profile.images;
     for (var album of profile.albums) {
       this.images = this.images.concat(album.images);
     }
    }, error => this.errorMessage = <any>error
   );
 }
}

Die Vorlage der übergeordneten Komponente enthält dies

...
<image-gallery [images]="images"></image-gallery>
...
Optimus Pette
quelle
1
Wie werden die imagesDaten in der übergeordneten Komponente ausgefüllt? Dh, ist es über eine http-Anfrage (n)? In diesem Fall ist es möglicherweise besser, wenn die ImageGalleryComponent das http-Observable abonniert ().
Mark Rajcok
@ MarkRajcok imagessind nur ein Teil der Daten, die vom Elternteil wie folgt verwendet werden. {profile: {firstName: "abc", lastName: "xyz", images: [ ... ]}}Wenn ich das Kind abonniere, muss ich mich immer noch für das Elternteil anmelden und ich möchte die Wiederholung vermeiden
Optimus Pette
Wenn das Bildarray in der übergeordneten Komponente beim Erstellen der untergeordneten Komponente gefüllt wird, sollte die Bildeingabeeigenschaft gefüllt werden, bevor ngOnInit () aufgerufen wird. Sie müssten weitere Informationen darüber bereitstellen, wie das Bildarray in der übergeordneten Komponente gefüllt ist, damit jeder Ihnen weiterhelfen kann (oder einen minimalen Plunker erstellen, der das Problem anzeigt).
Mark Rajcok
@MarkRajcok Ich habe die übergeordnete Komponente hinzugefügt und wie Bilder darin gefüllt werden.
Optimus Pette
2
Ja, es sieht so aus, als ob Ihre übergeordnete Komponente http verwendet (da sie einen Dienst verwendet), um ihre Images-Eigenschaft zu füllen. Da es sich um eine asynchrone Operation handelt, wird die Eingabeeigenschaft der untergeordneten Komponente zum Zeitpunkt des Aufrufs ihrer ngOnInit () -Methode nicht gefüllt. Verschieben Sie Ihren Code von ngOnInit () nach ngOnChanges () und es sollte funktionieren.
Mark Rajcok

Antworten:

84

Eingabeeigenschaften werden ausgefüllt, bevor sie ngOnInit()aufgerufen werden. Dies setzt jedoch voraus, dass die übergeordnete Eigenschaft, die die Eingabeeigenschaft speist, bereits beim Erstellen der untergeordneten Komponente ausgefüllt ist.

In Ihrem Szenario ist dies nicht der Fall - die Bilddaten werden asynchron von einem Dienst ausgefüllt (daher eine http-Anforderung). Daher wird die Eingabeeigenschaft beim ngOnInit()Aufruf nicht ausgefüllt .

Um Ihr Problem zu lösen, weisen Sie der übergeordneten Eigenschaft ein neues Array zu, wenn die Daten vom Server zurückgegeben werden. ngOnChanges()Im Kind implementieren . ngOnChanges()wird aufgerufen, wenn die Winkeländerungserkennung den neuen Array-Wert an das untergeordnete Element weitergibt.

Mark Rajcok
quelle
1
Ich stimme Ihnen zu, weil ich selbst mit demselben Problem konfrontiert war. Auch nachdem ich ngOnchanges()das Kind implementiert habe , kommt der Fehler Cannot read property '0' of undefined. Die App kann jedoch problemlos fortgesetzt werden. Dieser Fehler tritt auf, weil die Eingabeeigenschaft anfangs nicht ausgefüllt wurde. Es wird beim zweiten Aufruf ngOnChanges()ausgefüllt, wenn die Daten vom asynchronen Aufruf empfangen werden. Für meinen Fall habe ich zusätzlich zu dieser Lösung den Schutz gegen den Null- Operator im HTML hinzugefügt . Der Fehler wurde eindeutig behoben.
Thilina Samiddhi
5

Sie können auch einen Setter für Ihre Bilder hinzufügen, der aufgerufen wird, wenn sich der Wert ändert, und Sie können Ihr standardmäßig ausgewähltes Bild im Setter selbst festlegen:

export class ImageGalleryComponent {
  private _images: Image[];

  @Input()
  set images(value: Image[]) {
      if (value) { //null check
          this._images = value;
          this.selectedImage = value[0]; //setting default selected image
      }
  }
  get images(): Image[] {
      return this._images;
  }

  selectedImage: Image;
}
Sachin Parashar
quelle