为什么实现 css 和 *ngFor 的旋转木马不能动态地协同工作来获取图像 [英] Why carousel of materialize css and *ngFor not working together dynamicaly to get images
问题描述
我正在尝试实现旋转木马的角度代码.轮播与动态数组相关联,但是当我将 *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 class="carousel-item" href="#{{hrefs[i]}}!"*ngFor="let item of items;let i = index"><img src={{item}}/></a>
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:
<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>
在您的组件中,您现在只需要以下内容:
//导入//...导出类 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屋!