I have a list of items in my database. Each item has some entities and one of them is ImageFileName. This ImageFileName represents the file and its extension. I want to loop through the database and render all the images along with their other entities. The Html is:
<div *ngFor="let post of specialPosts">
<div >
<img [src]="GetImage(post.imageFileName)" [alt]="post.title" />
</div>
The component related to this Html is:
export class SpecialPostComponent implements OnInit {
constructor(private postService: PostService) { }
specialPosts: Post[] = [];
ngOnInit(): void {
this.GetSpecialPost();
}
GetSpecialPost() {
this.postService.GetSpecialPost().subscribe(
response => {
this.specialPosts = response;
// console.log(response);
}
);
}
CreateImageFromBlob(image: Blob) {
let reader = new FileReader();
if (image != null) {
reader.readAsDataURL(image);
reader.addEventListener("load", () => {
return = reader.result;
}, false);
}
}
GetImage(filename: string) {
this.postService.GetSpecialPostImage(filename).subscribe(
response => this.CreateImageFromBlob(response)
);
}
}
The service used for connecting to API is:
export class PostService {
constructor(private http: HttpClient) {
}
GetSpecialPost(): Observable<Post[]>{
return this.http.get<Post[]>(url.baseURL '/posts/getspecialpostslist');
}
}
GetSpecialPostImage(filename: string): Observable<Blob>{
return this.http.get(url.baseURL '/posts/getspecialpostimage?filename=' filename, {"responseType": "blob"});
}
}
The model:
export interface Post{
id: number,
title: string,
description: string,
creationDate: string,
isSpecialPost: boolean,
isMainPost: Boolean,
isActive: boolean,
imageFileName: string,
name: string
}
The problem is that when I build the project, CPU usage reaches 87% and the browser gets unresponsive and no images are delivered to the browser. How can I loop through images while the images come from API?
Update 1: I changed component code to this:
export class SpecialPostComponent implements OnInit {
constructor(private postService: PostService) { }
specialPosts: Post[] = [];
ImageToShow: any;
ngOnInit(): void {
this.GetSpecialPost();
}
GetSpecialPost() {
this.postService.GetSpecialPost().subscribe(
response => {
this.specialPosts = response;
this.PrepareImages(this.specialPosts);
// console.log(response);
}
);
}
PrepareImages(post: Post[]){
post.forEach(element => {
this.ImageToShow = this.GetImage(element.imageFileName);
});
}
CreateImageFromBlob(image: Blob) {
let reader = new FileReader();
if (image != null) {
reader.readAsDataURL(image);
reader.addEventListener("load", () => {
return reader.result;
}, false);
}
}
GetImage(filename: string) {
this.postService.GetSpecialPostImage(filename).subscribe(
response => this.CreateImageFromBlob(response)
);
}
}
But, images are not shown.
CodePudding user response:
My suggestion is to prepare images after you get specialPosts and then pass specialPosts with the correct image src to HTML.
import { forkJoin } from 'rxjs';
.
.
GetSpecialPost() {
this.postService.GetSpecialPost().subscribe(
response => {
this.specialPosts = response;
this.prepareImages(this.specialPosts);
}
);
}
CreateImageFromBlob(image: Blob): Promise<any> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.addEventListener('load', () => {
resolve(reader.result);
}, false);
if (image) {
reader.readAsDataURL(image);
} else {
reject();
}
});
}
prepareImages(posts: Post[]) {
forkJoin(
posts.map(post =>
this.postService.GetSpecialPostImage(post.filename).pipe(
mergeMap(async (response: Blob) => {
post.imageSrc = await this.CreateImageFromBlob(response);
return post;
}))
)
).subscribe((posts: Post[]) => {
this.reviseSpecialPosts = [...posts];
});
}
And in the HTML you just need to pass imageSrc:
<div *ngFor="let post of reviseSpecialPosts">
<div >
<img [src]="post?.imageSrc" [alt]="post.title" />
</div>
</div>