[英]Angular: In which lifecycle hook is input data available to the Component
I have a component which receives an array of image
objects as Input
data.我有一个组件,它接收一组
image
对象作为Input
数据。
export class ImageGalleryComponent {
@Input() images: Image[];
selectedImage: Image;
}
I would like when the component loads the selectedImage
value be set to the first object of the images
array.我想在组件加载
selectedImage
值时将其设置为images
数组的第一个对象。 I have tried to do this in the OnInit
lifecycle hook like this:我试图在
OnInit
生命周期钩子中这样做:
export class ImageGalleryComponent implements OnInit {
@Input() images: Image[];
selectedImage: Image;
ngOnInit() {
this.selectedImage = this.images[0];
}
}
this gives me an error Cannot read property '0' of undefined
which means the images
value isn't set on this stage.这给了我一个错误
Cannot read property '0' of undefined
这意味着images
值未在此阶段设置。 I have also tried the OnChanges
hook but I'm stuck because i can't get information on how to observe changes of an array.我也尝试过
OnChanges
钩子,但我被卡住了,因为我无法获得有关如何观察数组变化的信息。 How can I achieve the expected result?我怎样才能达到预期的结果?
The parent component looks like this:父组件如下所示:
@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
);
}
}
The parent component's template has this父组件的模板有这个
...
<image-gallery [images]="images"></image-gallery>
...
Input properties are populated before ngOnInit()
is called.在
ngOnInit()
之前填充输入属性。 However, this assumes the parent property that feeds the input property is already populated when the child component is created.但是,这假设在创建子组件时已经填充了提供输入属性的父属性。
In your scenario, this is not the case – the images data is being populated asynchronously from a service (hence an http request).在您的场景中,情况并非如此——图像数据是从服务异步填充的(因此是 http 请求)。 Therefore, the input property will not be populated when
ngOnInit()
is called.因此,调用
ngOnInit()
时不会填充输入属性。
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()
。 ngOnChanges()
will be called when Angular change detection propagates the new array value down to the child.当 Angular 更改检测将新数组值向下传播到子级时,将调用
ngOnChanges()
。
You can also add a setter for your images which will be called whenever the value changes and you can set your default selected image in the setter itself:您还可以为您的图像添加一个设置器,每当值更改时都会调用该设置器,您可以在设置器本身中设置默认选择的图像:
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;
}
You can resolve it by simply changing few things.你可以通过简单地改变一些东西来解决它。
export class ImageGalleryComponent implements OnInit {
@Input() images: Image[];
selectedImage: Image;
ngOnChanges() {
if(this.images) {
this.selectedImage = this.images[0];
}
}
}
And as another one solution, you can simply *ngIf
all template content until you get what you need from network:作为另一种解决方案,您可以简单地
*ngIf
所有模板内容,直到您从网络中获得所需内容:
...
<image-gallery *ngIf="imagesLoaded" [images]="images"></image-gallery>
...
And switch flag value in your fetching method:并在您的获取方法中切换标志值:
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
);
}
In this way you will renderout child component only when parent will have all what child needs in static content.通过这种方式,只有当父组件在静态内容中拥有子组件所需的所有内容时,您才会渲染子组件。 It's even more useful when you have some loaders/spinners that represent data fetching state:
当您有一些表示数据获取状态的加载器/微调器时,它会更有用:
...
<image-gallery *ngIf="imagesLoaded" [images]="images"></image-gallery>
<loader-spinner-whatever *ngIf="!imagesLoaded" [images]="images"></loader-spinner-whatever>
...
But short answer to your questions:但对您的问题的简短回答:
OnInit
hookOnInit
钩子中undefined
input stateundefined
输入状态
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.