我的模型在帖子和 Img 之间存在一对多的关系,即每个帖子都有一些 Img 。显示此结构的简化方法之一是:
<ul>
<li *ngFor="let post of posts">
{{post.postId}}
<p *ngFor="let img of getImgs(post.postId)">{{img.url}}</p>
</li>
</ul>
我的问题是由于Angular的变化检测机制,页面进入无限循环。有没有更好的方法来重构此代码? (我正在使用 Angular 5 )我的代码的简化版如下:
我的AppComponent看起来像:
import { Component } from '@angular/core';
import {Post} from "./post"
import {PostService} from "./post.service";
import {Observable} from "rxjs/Observable";
import {Img} from "./img";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [PostService]
})
export class AppComponent {
title = 'app';
posts : Post[];
constructor(private postService: PostService) { }
ngOnInit(): void {
this.getPosts();
}
getPosts(): void {
this.postService.getPosts().subscribe(posts => this.posts = posts);
}
getImgs(postId : string) : Img[] {
var retImgs : Img[];
this.postService.getImgsByPostId(postId).subscribe( imgs => retImgs = imgs);
return retImgs;
}
}
我从Web服务获得发布和 Img 。 帖子不包含 Img 作为其自身的一部分,但使用 postId Img >。如果我想将此模型保留在 Img 不属于帖子的位置,我发现很难存储 Img 在AppCompnent
。这迫使我将getImgs()
调用放入HTML模板中,每次更改检测事件都会调用该模板。 Angular 5处理这种情况的正常方法是什么?
我可以做一些黑客来保存/缓存getImgs()
的输出,所以我不需要为后续请求调用Web服务,或者我可以只改变我的模型,但我想知道这是怎么回事通常都会完成。
无论如何都要从模板中调用一个方法,以便不会在每个变更检测机制上调用它?
修改
为了回应@ Floor 建议使用更智能的getImgs()
来缓存Map
中的图片,我尝试了以下AppComponent
:( Imports和Component Decorator如上所述)
export class AppComponent {
title = 'app';
posts : Post[];
postIdToImgs : Map<string, Img[]>; //Added
constructor(private postService: PostService) {
this.postIdToImgs = new Map<string, Img[]>(); //Added
}
ngOnInit(): void {
this.getPosts();
}
getPosts(): void {
this.postService.getPosts().subscribe(posts => this.posts = posts);
}
getImgs(postId : string) : Img[] {
var retImgs : Img[];
console.log(`Call to getImgs(${postId})`); //Added
if(this.postIdToImgs.has(postId)) { //Added
console.log('Found value in Cache'); //Added
retImgs = this.postIdToImgs.get(postId); //Added
return retImgs; //Added
} //Added
this.postService.getImgsByPostId(postId).subscribe( imgs => {
this.postIdToImgs.set(postId, imgs); //Added
retImgs = imgs;
});
return retImgs;
}
}
是的,这会在第一次迭代后停止对后端的调用,但我仍然得到无限序列
Cal to getImgs(#postId)
在Cache中找到值
其中#postId是此页面上的10个帖子之一。我正在努力学习Angular,所以我不是想让它发挥作用。我试图找出:
有没有办法让模板中的方法/功能在每次更改检测时都没有调用?
答案 0 :(得分:2)
解决此问题的最佳方法是将两个对象放入包装器中。 使用帖子及其所属图像填充此包装器。 然后执行ngFor使用这个包装器。
e.g。
<ul>
<li *ngFor="let wrapper of myWrapperList">
{{wrapper?.post?.postId}}
<p *ngFor="let img of wrapper.images">{{img?.url}}</p>
</li>
</ul>
在你的模板中
$project
答案 1 :(得分:2)
您可以将代码移动到管道,每次发生更改检测时都不会调用该管道
https://angular.io/guide/pipes#pure-pipes
@Pipe({
name: 'getImages',
})
export class GetImagesPipe implements PipeTransform {
postIdToImgs : Map<string, Img[]> = new Map<string, Img[]>();
constructor(private postService: PostService) { }
transform(postId: string): any {
var retImgs : Img[];
console.log(`IN PIPE: Call to getImgs(${postId})`);
/*This commented cache implementation is not needed as the pipe won't be called again if the post does not change
if(this.postIdToImgs.has(postId)) {
console.log('IN PIPE: Found value in Cache');
retImgs = this.postIdToImgs.get(postId);
return retImgs;
} */
this.postService.getImgsByPostId(postId).subscribe( imgs => {
this.postIdToImgs.set(postId, imgs); //Added
retImgs = imgs;
});
return retImgs;
}
}
我创建了一个stackblitz https://stackblitz.com/edit/angular-9n9h18?file=app%2Fimg.pipe.ts