Angular 重新构造代码以避免角度变化检测无限循环
我的模型在Post和Imgs之间有一对多的关系,即每个Post都有一些Imgs。显示此结构的简化方法之一是:Angular 重新构造代码以避免角度变化检测无限循环,angular,angular5,Angular,Angular5,我的模型在Post和Imgs之间有一对多的关系,即每个Post都有一些Imgs。显示此结构的简化方法之一是: <ul> <li *ngFor="let post of posts"> {{post.postId}} <p *ngFor="let img of getImgs(post.postId)">{{img.url}}</p> </li> </ul> 我从Web服务中获得Pos
<ul>
<li *ngFor="let post of posts">
{{post.postId}}
<p *ngFor="let img of getImgs(post.postId)">{{img.url}}</p>
</li>
</ul>
我从Web服务中获得Posts和Imgs。Posts不包含作为其一部分的Imgs,但是Imgs是使用postId检索的。如果我想保留Imgs不属于Posts的模型,我发现很难将Imgs存储在appcomponent
中。这迫使我将getImgs()
调用放在HTML模板中,每个更改检测事件都会调用该模板。Angular 5中处理此场景的正常方式是什么
当然,我可以做一些修改来保存/缓存getImgs()
的输出,因此我不需要为后续请求调用Web服务,或者我可以更改我的模型,但我想知道这通常是如何做到的
是否有必要从模板中调用一个方法,这样就不会在每个更改检测机制中调用它
编辑 为了响应@Floor的建议,使用更智能的
getImgs()
将图像缓存在地图中,我尝试了以下AppComponent
:(导入和组件装饰器如上所述)
导出类AppComponent{
标题=‘应用程序’;
职位:职位[];
postdtoimgs:Map;//已添加
建造商(私人邮政服务:邮政服务){
this.positdToimgs=new Map();//已添加
}
ngOnInit():void{
这是getPosts();
}
getPosts():void{
this.postService.getPosts().subscribe(posts=>this.posts=posts);
}
getImgs(postId:string):Img[]{
var retImgs:Img[];
log(`calltogetimgs(${postId})`);//添加
如果(this.postdtoimgs.has(postId)){//添加了
console.log('在缓存中找到值');//已添加
retImgs=this.postdtoimgs.get(postId);//已添加
return retImgs;//已添加
}//增加
this.postService.getImgsByPostId(postId).subscribe(imgs=>{
this.postedtoimgs.set(postId,imgs);//已添加
retImgs=imgs;
});
返回重定时;
}
}
是的,这会在第一次迭代后停止对后端的调用,但我仍然会得到一个无限的调用序列
Cal to getImgs(#posted)
在缓存中找到值
其中#posted是我在本页上的10篇帖子之一。我在努力学习角度,所以我不只是想让它发挥作用。我想知道:
是否有一种方法可以使模板中的方法/函数在每次更改检测时都不被调用?
解决此问题的最佳方法是将两个对象都放入包装器中。
用帖子和它所属的图片填充这个包装。
然后执行使用此包装器的步骤
e、 g
从'@angular/core'导入{Component};
从“/Post”导入{Post}
从“/post.service”导入{PostService}”;
从“rxjs/Observable”导入{Observable};
从“/Img”导入{Img};
@组成部分({
选择器:'应用程序根',
templateUrl:“./app.component.html”,
样式URL:['./app.component.css'],
提供者:[邮政服务]
})
导出类AppComponent{
标题=‘应用程序’;
myWrapperList:Array=[];
构造器(私人邮政服务:邮政服务){}
ngOnInit():void{
this.init();
}
init():void{
this.postService.getPosts().subscribe(posts=>
posts.forEach(post=>{
this.postService.getImgsByPostId(post.postId).subscribe(imgs=>
让myWrapper=newmywrapper(post,imgs);
this.myWrapperList.push(myWrapper);
});
);
}
}
导出类MyWrapper{
建造师(
公共职务:职务,,
公共图像:阵列
){}
}
在你的模板中
<ul>
<li *ngFor="let wrapper of myWrapperList">
{{wrapper?.post?.postId}}
<p *ngFor="let img of wrapper.images">{{img?.url}}</p>
</li>
</ul>
-
{{wrapper?.post?.posted}}
{{{img?.url}
解决此问题的最佳方法是将两个对象都放入包装器中。
用帖子和它所属的图片填充这个包装。
然后执行使用此包装器的步骤
e、 g
从'@angular/core'导入{Component};
从“/Post”导入{Post}
从“/post.service”导入{PostService}”;
从“rxjs/Observable”导入{Observable};
从“/Img”导入{Img};
@组成部分({
选择器:'应用程序根',
templateUrl:“./app.component.html”,
样式URL:['./app.component.css'],
提供者:[邮政服务]
})
导出类AppComponent{
标题=‘应用程序’;
myWrapperList:Array=[];
构造器(私人邮政服务:邮政服务){}
ngOnInit():void{
this.init();
}
init():void{
this.postService.getPosts().subscribe(posts=>
posts.forEach(post=>{
this.postService.getImgsByPostId(post.postId).subscribe(imgs=>
让myWrapper=newmywrapper(post,imgs);
this.myWrapperList.push(myWrapper);
});
);
}
}
导出类MyWrapper{
建造师(
公共职务:职务,,
公共图像:阵列
){}
}
在你的模板中
<ul>
<li *ngFor="let wrapper of myWrapperList">
{{wrapper?.post?.postId}}
<p *ngFor="let img of wrapper.images">{{img?.url}}</p>
</li>
</ul>
-
{{wrapper?.post?.posted}}
{{{img?.url}
您可以将代码移动到管道中,而不是每次发生更改检测时都调用管道
@管道({
名称:'getImages',
})
导出类GetImagesPipe实现PipeTransform{
postdtoimgs:Map=newmap();
构造器(私人邮政服务:邮政服务){}
转换(postId:string):任意{
var retImgs:Img[];
log(`IN-PIPE:calltogetimgs(${postId})`);
/*作为pip,不需要此注释缓存实现
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';
myWrapperList: Array<MyWrapper> = [];
constructor(private postService: PostService) { }
ngOnInit(): void {
this.init();
}
init(): void {
this.postService.getPosts().subscribe( posts =>
posts.forEach(post => {
this.postService.getImgsByPostId(post.postId).subscribe(imgs =>
let myWrapper = new MyWrapper(post, imgs);
this.myWrapperList.push(myWrapper);
});
);
}
}
export class MyWrapper {
constructor(
public post: Post,
public images: Array<Images>
){}
}
<ul>
<li *ngFor="let wrapper of myWrapperList">
{{wrapper?.post?.postId}}
<p *ngFor="let img of wrapper.images">{{img?.url}}</p>
</li>
</ul>
@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;
}
}