Why carousel of materialize css and *ngFor not working together dynamicaly to get images

落花浮王杯 提交于 2021-02-08 08:11:10

问题


I'm trying to materialize angular code for carousel. The carousel is associated to a dynamic array but when i use *ngFor with carousel class its not working.

I tried writing the class="carousel-item" inside for loop but console shows:

Cannot read property 'clientWidth' of undefined.

This code not working:

Template:

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

Component:

options = {fullWidth: false};

constructor(private http: HttpClient) {
}

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

I'm only getting one image that too which is cropped in half where as if i remove the for loop and write <div class="carousel-item"> one after the other like:

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

Doing this, I get the carousel working but it is not binded to a dynamic array which is what i want.


回答1:


Instead of initialising the carousel in OnInit use the AfterViewInit lifecycle hook

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

In addition change your template like this:

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

*ngFor on the a-tag will create the structure required by materialize.

Using the index of the current element and a new array called 'hrefs', the href attribute is set individually for each a-tag.

Please checkout this Stackblitz for a working example.

Edit: With API response

The error "Can not read property 'clientWidth' of undefined" appears now (as well as during the initialization of the carousel within OnInit), because at the time the M.Carousel.init (...) is called the HTML structure is not complete yet. As long as this.items is undefined, there are no a-tags with class carousel-item.

To work around the problem, the initialization of the materialize carousel must be delayed until the data is loaded from the server and all a-tags were added to the DOM by *ngFor.

// removed code because it wasn't the best solution..
// it's still in the Stackblitz as comment

Edit #2

I just realized that there is a better method: instead of setting a timeout on the initialization of the carousel, let the *ngFor trigger the init after it's done adding the last item to the DOM. To do so, change your html like this:

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

In your component you will only need the following now:

// 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"]);
  }
}

Adjusted Stackblitz.



来源:https://stackoverflow.com/questions/55667029/why-carousel-of-materialize-css-and-ngfor-not-working-together-dynamicaly-to-ge

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!