角度:在哪个生命周期挂钩中输入组件可用的数据


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 subscription()绑定到http observable。
Mark Rajcok '16

@MarkRajcokimages只是这样的父母使用的数据的一部分,{profile: {firstName: "abc", lastName: "xyz", images: [ ... ]}}这意味着如果我订阅孩子,我仍然必须订阅父母,并且我想避免重复
Optimus Pette

如果在创建子组件时填充了父组件中的images数组,则应在调用ngOnInit()之前填充images输入属性。您将需要提供有关如何在父组件中填充images数组的更多信息,以便任何人进一步帮助您(或创建一个显示问题的最小Plunker)。
Mark Rajcok '16

@MarkRajcok我已经添加了父组件以及如何在其中填充图像。
Optimus Pette

2
因此,是的,看起来您的父组件正在使用http(因为它正在使用服务)来填充其images属性。由于这是异步操作,因此在调用其子组件的ngOnInit()方法之前不会填充子组件的输入属性。将您的代码从ngOnInit()移到ngOnChanges(),它应该可以工作。
Mark Rajcok '16

Answers:


84

ngOnInit()调用之前填充输入属性。但是,这假定在创建子组件时已经填充了用于输入属性的父属性。

在您的方案中,情况并非如此-图像数据是从服务异步填充的(因此发出http请求)。因此,在ngOnInit()调用时将不会填充input属性。

为了解决您的问题,当从服务器返回数据时,请为父属性分配一个新数组。ngOnChanges()在孩子身上实施。 ngOnChanges()当角度变化检测将新的数组值传播到子级时,将调用。


1
我同意你的看法,因为我本人也面临同样的问题。即使我ngOnchanges()在孩子身上实施了该工具,也会出现错误Cannot read property '0' of undefined。但是,该应用程序可以顺利进行。出现此错误的原因是,最初并未填充input属性。ngOnChanges()当第二次调用接收到来自异步调用的数据时,将填充它。就我而言,除了此解决方案之外,我还在html中添加了针对null运算符的防护。它清楚地解决了该错误。
Thilina Samiddhi

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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.