为什么实现 css 和 *ngFor 的旋转木马不能动态地协同工作来获取图像 [英] Why carousel of materialize css and *ngFor not working together dynamicaly to get images

查看:266
本文介绍了为什么实现 css 和 *ngFor 的旋转木马不能动态地协同工作来获取图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现旋转木马的角度代码.轮播与动态数组相关联,但是当我将 *ngFor 与轮播类一起使用时,它不起作用.

我尝试在 for 循环中编写 class="carousel-item" 但控制台显示:

<块引用>

无法读取未定义的属性clientWidth".

此代码不起作用:

模板:

组件:

options = {fullWidth: false};构造函数(私有 http:HttpClient){}ngOnInit() {var elems = document.querySelectorAll('.carousel');var 实例 = 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>

这样做后,轮播可以正常工作,但它没有绑定到我想要的动态数组.

解决方案

不要在 OnInit 中初始化 carousel,而是使用 AfterViewInit 生命周期钩子

import { Component, OnInit, AfterViewInit } from '@angular/core';//其他进口@成分({选择器:'我的应用',templateUrl: './app.component.html',styleUrls: ['./app.component.css']})导出类 AppComponent 实现 OnInit, AfterViewInit {//...构造函数(私有 http:HttpClient){}ngOnInit() {}ngAfterViewInit() {var elems = document.querySelectorAll('.carousel');var 实例 = M.Carousel.init(elems, this.options);}}

另外像这样改变你的模板:

a-tag 上的

*ngFor 将创建 materialize 所需的结构.

使用当前元素的索引和一个名为hrefs"的新数组,为每个 a-tag 单独设置 href 属性.

请查看此 Stackblitz 以获取工作示例.

使用 API 响应

现在出现错误Can not read property 'clientWidth' of undefined"(以及在 OnInit 中的轮播初始化期间),因为当时 M.Carousel.init (...) 被称为 HTML 结构尚未完成.只要 this.items 未定义,就没有带有 carousel-item 类的 a 标签.

要解决此问题,必须延迟实体化轮播的初始化,直到数据从服务器加载并且所有 a 标签都通过 *ngFor 添加到 DOM 中.

//删除了代码,因为它不是最好的解决方案..//它仍然在 Stackblitz 中作为评论

编辑 #2

我刚刚意识到有一个更好的方法:不是在轮播初始化时设置超时,而是让 *ngFor 在完成将最后一项添加到 DOM 后触发 init.为此,请像这样更改您的 html:

在您的组件中,您现在只需要以下内容:

//导入//...导出类 AppComponent 实现 OnInit {//...ngOnInit() {//虚拟 api 请求this.fakeApiRequest().pipe(delay(2000)).subscribe((res) => {//解析api响应this.items = res;});}initCarousel() {//需要超时,否则导航将无法工作.setTimeout(() => {让 elems = document.querySelectorAll('.carousel');让实例 = M.Carousel.init(elems, this.options);}, 100);}fakeApiRequest(): Observable{返回(["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.

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.

解决方案

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.

这篇关于为什么实现 css 和 *ngFor 的旋转木马不能动态地协同工作来获取图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆