У меня есть компонент, который получает массив 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>
...
javascript
angular
typescript
Оптимус Петте
источник
источник
images
данные заполняются в родительском компоненте? Т.е. через HTTP-запрос (-ы)? Если это так, вам может быть лучше иметь ImageGalleryComponent subscribe () к наблюдаемому http.images
- это всего лишь часть данных, которые используются таким родителем,{profile: {firstName: "abc", lastName: "xyz", images: [ ... ]}}
что означает, что если я подпишусь в дочернем элементе , мне все равно придется подписываться на родительский элемент, и я бы хотел избежать повторенияОтветы:
Свойства ввода заполняются до
ngOnInit()
вызова. Однако при этом предполагается, что родительское свойство, которое передает свойство input, уже заполнено при создании дочернего компонента.В вашем сценарии это не так - данные изображений заполняются асинхронно из службы (следовательно, HTTP-запрос). Следовательно, свойство input не будет заполнено при
ngOnInit()
вызове.Чтобы решить вашу проблему, когда данные возвращаются с сервера, назначьте новый массив родительскому свойству. Реализуйте
ngOnChanges()
в детстве.ngOnChanges()
будет вызываться, когда обнаружение изменения Angular распространяет новое значение массива на дочерний элемент.источник
ngOnchanges()
в ребенка, ошибкаCannot read property '0' of undefined
вылетает. Но приложение может работать без проблем. Эта ошибка возникает из-за того, что изначально свойство input не было заполнено. Он заполняется при втором вызовеngOnChanges()
при получении данных из асинхронного вызова. В моем случае, в дополнение к этому решению, я добавил защиту от нулевого оператора в html. Это явно решило ошибку.Вы также можете добавить сеттер для своих изображений, который будет вызываться при изменении значения, и вы можете установить выбранное изображение по умолчанию в самом сеттере:
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]; } } }
источник