Почему карусель материализации css и * ngДля динамической работы вместе, чтобы получить изображения - PullRequest
1 голос
/ 13 апреля 2019

Я пытаюсь материализовать угловой код для карусели. Карусель связана с динамическим массивом, но когда я использую *ngFor с классом карусели, он не работает.

Я пытался написать class="carousel-item" внутри для цикла, но консоль показывает:

Невозможно прочитать свойство clientWidth из неопределенного.

Этот код не работает:

Шаблон:

<div class="carousel carousel-slider">
    <div class="carousel-item" href="#one!">
       <div *ngFor ="let item of items;let i = index">
           <img src={{items[i]}}>
        </div>
    </div>
</div>

Компонент:

options = {fullWidth: false};

constructor(private http: HttpClient) {
}

ngOnInit() {
    var elems = document.querySelectorAll('.carousel');
    var instances = M.Carousel.init(elems, this.options);
}

Я получаю только одно изображение, которое тоже обрезается пополам, как будто я удаляю цикл for и пишу <div class="carousel-item"> одно за другим, например:

<a class="carousel-item" href="#one!"><img src={{items[0]}}></a>
<a class="carousel-item" href="#two!"><img src={{items[1]}}></a>
<a class="carousel-item" href="#three!"><img src={{items[2]}}></a>

Делая это, я заставляю карусель работать, но она не привязана к динамическому массиву, что я и хочу.

1 Ответ

2 голосов
/ 14 апреля 2019

Вместо инициализации карусели в 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 .

...