Вместо инициализации карусели в OnInit
используйте AfterViewInit
крюк жизненного цикла
import { Component, OnInit, AfterViewInit } from '@angular/core';
// other imports
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, AfterViewInit {
// ...
constructor(private http: HttpClient) {}
ngOnInit() {}
ngAfterViewInit() {
var elems = document.querySelectorAll('.carousel');
var instances = M.Carousel.init(elems, this.options);
}
}
Кроме того, измените ваш шаблон следующим образом:
<div class="carousel">
<a class="carousel-item" href="#{{hrefs[i]}}!" *ngFor="let item of items;let i = index">
<img src={{item}}/>
</a>
</div>
*ngFor
на теге a создаст структуру, необходимую для материализации.
Используя индекс текущего элемента и новый массив с именем 'hrefs', атрибут href устанавливается индивидуально для каждого a-тега.
Пожалуйста, проверьте это Stackblitz для рабочего примера.
Редактировать: с ответом API
Появляется ошибка «Не удается прочитать свойство clientWidth of undefined» (а также во время инициализации карусели в OnInit), поскольку в момент вызова M.Carousel.init (...)
структура HTML еще не завершена. Пока this.items
не определено, a-теги с классом carousel-item
.
отсутствуют.
Чтобы обойти эту проблему, инициализация материализованной карусели должна быть отложена до тех пор, пока данные не будут загружены с сервера и все a-теги не будут добавлены в DOM с помощью *ngFor
.
// removed code because it wasn't the best solution..
// it's still in the Stackblitz as comment
Редактировать # 2
Я только что понял, что есть лучший метод: вместо установки времени ожидания при инициализации карусели, позвольте *ngFor
вызвать инициализацию после того, как он завершит добавление последнего элемента в DOM. Для этого измените ваш html следующим образом:
<div class="carousel">
<a class="carousel-item" href="#{{hrefs[i]}}!" *ngFor="let item of items;let i = index; let last = last">
<img src={{item}}/>
<ng-container *ngIf="last">{{initCarousel()}}</ng-container>
</a>
</div>
В вашем компоненте вам сейчас понадобится только следующее:
// imports
// ...
export class AppComponent implements OnInit {
// ...
ngOnInit() {
// dummy api request
this.fakeApiRequest().pipe(delay(2000)).subscribe((res) => {
// parse api response
this.items = res;
});
}
initCarousel() {
// timeout needed, otherwise navigation won't work.
setTimeout(() => {
let elems = document.querySelectorAll('.carousel');
let instances = M.Carousel.init(elems, this.options);
}, 100);
}
fakeApiRequest(): Observable<string[]> {
return of(["https://picsum.photos/200/300?image=0", "https://picsum.photos/200/300?image=1", "https://picsum.photos/200/300?image=2", "https://picsum.photos/200/300?image=3", "https://picsum.photos/200/300?image=4"]);
}
}
Скорректировано Stackblitz .