Angular:どのライフサイクルフックがコンポーネントで利用可能な入力データであるか


82

imageオブジェクトの配列をInputデータとして受け取るコンポーネントがあります。

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

コンポーネントがロードされるときに、selectedImage値がimages配列の最初のオブジェクトに設定されるようにしたいと思います。私は次のOnInitようなライフサイクルフックでこれを実行しようとしました:

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

これによりエラーが発生します。Cannot read property '0' of undefinedこれは、imagesこのステージで値が設定されていないことを意味します。OnChangesフックも試しましたが、配列の変化を観察する方法がわからないので行き詰まりました。どうすれば期待した結果を達成できますか?

親コンポーネントは次のようになります。

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

親コンポーネントのテンプレートにはこれがあります

...
<image-gallery [images]="images"></image-gallery>
...

1
images親コンポーネントにデータがどのように入力されていますか?つまり、httpリクエスト経由ですか?もしそうなら、ImageGalleryComponent subscribe()をhttpobservableに持っている方が良いかもしれません。
Mark Rajcok 2016年

@MarkRajcokimagesは、このように親が使用するデータの一部にすぎませ{profile: {firstName: "abc", lastName: "xyz", images: [ ... ]}}ん。つまり、子をサブスクライブする場合でも、親をサブスクライブする必要があり、繰り返しを避けたいと思います
Optimus Pette 2016年

子コンポーネントの作成時に親コンポーネントのimages配列にデータが入力されている場合は、ngOnInit()を呼び出す前に画像入力プロパティにデータを入力する必要があります。さらに役立つように(または問題を示す最小限のプランカーを作成するために)、親コンポーネントに画像配列がどのように入力されるかについての詳細情報を提供する必要があります。
Mark Rajcok 2016年

@MarkRajcok親コンポーネントと、そのコンポーネントに画像を入力する方法を追加しました。
Optimus Pette 2016年

2
そうです、親コンポーネントは(サービスを使用しているため)httpを使用してそのimagesプロパティにデータを入力しているようです。これは非同期操作であるため、子コンポーネントのinputプロパティは、そのngOnInit()メソッドが呼び出されるまでに入力されません。コードをngOnInit()からngOnChanges()に移動すると、機能するはずです。
Mark Rajcok 2016年

回答:


84

入力プロパティは、ngOnInit()が呼び出される前に入力されます。ただし、これは、子コンポーネントの作成時に、入力プロパティをフィードする親プロパティがすでに入力されていることを前提としています。

あなたのシナリオでは、これは当てはまりません–画像データはサービスから非同期に入力されています(したがってhttpリクエスト)。したがって、ngOnInit()が呼び出されたときにinputプロパティは設定されません。

問題を解決するには、サーバーからデータが返されるときに、親プロパティに新しい配列を割り当てます。ngOnChanges()子に実装します。 ngOnChanges()角度変化検出が新しい配列値を子に伝播するときに呼び出されます。


1
私自身も同じ問題に直面したので、私はあなたに同意します。ngOnchanges()子に実装した後でも、エラーCannot read property '0' of undefinedが発生します。しかし、アプリは問題なく続行できます。このエラーは、最初は入力プロパティが入力されていないために発生します。これはngOnChanges()、非同期呼び出しからのデータが受信されたときの2回目の呼び出しによって入力されます。私の場合、このソリューションに加えて、htmlにnull演算子に対するガードを追加しました。それは明らかにエラーを解決しました。
Thilina Samiddhi 2017

5

また、値が変更されるたびに呼び出される画像のセッターを追加したり、デフォルトで選択した画像をセッター自体に設定したりすることもできます。

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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.