Victoria
Victoria

Reputation: 187

Showing loading spinner while fetching the local data

I am having difficulties understanding the following:

I have an Image object:

export class Image {
  id: string;
  imageName: string;
  imageDesc: string;
  base64?: string;  // optional for future converting
}

I then define an array of objects:

export const mockImages: Image[] = [
  {
    id: 'image1',
    imageName: 'image1.jpg',
    imageDesc: 'Description of the first picture.',
  },
  {
    id: 'image2',
    imageName: 'image2.jpg',
    imageDesc: 'Description of the second picture.',
  },
  {
    id: 'image3',
    imageName: 'image3.jpg',
    imageDesc: 'Description of the third picture.',
  }
]

In the ts file I load the data and also start the conversion

ngOnInit(): void {
    this.imageData = mockImages;
    this.myService.convertImg();
  }

In my html, I loop through this data, and while they don´t have specified the fourth parameter base64, I want to conditionaly show loading spinner instead of the image:

<div *ngFor="let data of imageData; let i = index">
  <div [hidden]="!data[i]?.base64">
     <img
        (click)="onPreviewImage(i)"
        [src]="data.base64"
        [alt]="data.imageDesc"
     />
   </div>
   <app-loading-tab [hidden]="data[i]?.base64"></app-loading-tab>
</div>

convertImg() function in the myService. I am also defining the mockImages and mockImagesPath property.

convertImg(): void {
    const numberOfFiles = this.mockImages.length;
    for (let i = 0; i < numberOfFiles; i++) {
      this.http
        .get(`${this.mockImagesPath}/${this.mockImages[i].imageName}`, {responseType: 'blob'})
        .subscribe((res) => {
          const reader = new FileReader();
          reader.onloadend = () => {
            this.mockImages[i].base64 = reader.result as string;
          };
          reader.readAsDataURL(res);
        });
    }
  }

But this approach is not doing what I would expect - which is conditionally show and hide loader while data is being loaded / and is already displayed. I always see the loading spinners as if the conversion was not recognized.

Can you tell me what am I doing wrong?

Upvotes: 0

Views: 452

Answers (1)

Csaba
Csaba

Reputation: 31

My suggestion would be to create a Subject on your service class, something like

public imageConverted = new Subject<Image>();

Then in your convert method, notify whenever an image is done converting:

convertImg(): void {
    const numberOfFiles = this.mockImages.length;
    for (let i = 0; i < numberOfFiles; i++) {
      this.http
        .get(`${this.mockImagesPath}/${this.mockImages[i].imageName}`, {responseType: 'blob'})
        .subscribe((res) => {
          const reader = new FileReader();
          reader.onloadend = () => {
            this.mockImages[i].base64 = reader.result as string;
            this.imageConverted.next(this.mockImages[i]);
          };
          reader.readAsDataURL(res);
          
        });
    }
  }

Finally in your component subscribe to the event and update the image that's done converting:

ngOnInit(): void {
    this.imageData = mockImages;
    this.myService.imageConverted.subscribe({
        next: (image) => {
            const index = this.imageData.findIndex(i => i.id === image.id);
            if (index > -1) {
               this.imageData[index] = image;
            }
        }
    });
    this.myService.convertImg();
  }

Upvotes: 1

Related Questions