角度: 其中生命周期钩子是组件可用的输入数据

我有一个组件,它接收作为 Input数据的 image对象数组。

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>
...
52721 次浏览

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

在您的场景中,图像数据不是从服务异步填充的(因此是 http 请求)。因此,在调用 ngOnInit()时不会填充 input 属性。

To solve your problem, when the data is returned from the server, assign a new array to the parent property. Implement ngOnChanges() in the child. ngOnChanges() will be called when Angular change detection propagates the new array value down to the child.

你也可以为你的图像添加一个 setter,每当值改变时就会调用它,你可以在 setter 中设置默认选择的图像:

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

您可以通过简单地改变一些事情来解决这个问题。

  export class ImageGalleryComponent implements OnInit {


@Input() images: Image[];
selectedImage: Image;


ngOnChanges() {
if(this.images) {
this.selectedImage = this.images[0];
}
}


}

作为另一种解决方案,你可以简单地 *ngIf所有的模板内容,直到你从网络得到你需要的:

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

并在抓取方法中切换标志值:

  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);
}
this.imagesLoaded = true; /* <--- HERE*/
}, error => this.errorMessage = <any>error
);
}

这样,只有当父级在静态内容中包含所有子级需要的内容时,才会渲染子组件。当您有一些表示数据获取状态的加载程序/旋转程序时,它甚至更加有用:

...
<image-gallery *ngIf="imagesLoaded" [images]="images"></image-gallery>
<loader-spinner-whatever *ngIf="!imagesLoaded" [images]="images"></loader-spinner-whatever>
...

但请简短回答你的问题:

  • 什么时候输入可用?
    • OnInit钩子里
  • 为什么子组件不可用?
    • 是的,但是在这个特定的时间点,它们没有被装载
  • 我能用这个做什么?
    • 耐心等待呈现子组件 utul,以异步方式获取数据或学习子组件处理 undefined输入状态