(FRONT) FRONT (2025)

Loading images asynchronously (Angular, Axios, jQuery, XMLHttpRequest, Html5).
Angular async pipe with Promise and Observable.

1. XMLHttpRequest - most ancient way to working with Images, already embedded to Browser


XMLHttpRequest is most important object in Javascript, you can detect - is this object present, you code working in Browser, otherwise in Node.JS or other environment (for example Windows desktop JS engine - Windows Script Host).


   1:  if (typeof XMLHttpRequest !== 'undefined') {
   2:    console.log('XMLHttpRequest is available. Running in a browser.');
   3:  } else {
   4:    console.log('XMLHttpRequest is not available. Not running in a browser.');
   5:  }

https://github.com/AAlex-11/ImageAsync/blob/main/Html/XHR.htm


   1:  <!DOCTYPE html>
   2:  <html lang="en">
   3:  <head>
   4:    <meta charset="UTF-8">
   5:    <meta name="viewport" content="width=device-width, initial-scale=1.0">
   6:    <title>Load Image with XMLHttpRequest</title>
   7:  </head>
   8:  <body>
   9:    <div id="image-container">
  10:      <!-- The image will be inserted here -->
  11:    </div>
  12:   
  13:    <script>
  14:      // URL of the image to load
  15:      const imageUrl = 'http://localhost:3000/images/Frontend.png';
  16:   
  17:      // Create a new XMLHttpRequest object
  18:      const xhr = new XMLHttpRequest();
  19:   
  20:      // Configure the request
  21:      xhr.open('GET', imageUrl, true);
  22:      xhr.responseType = 'blob'; // We expect the response to be a binary blob (image)
  23:   
  24:      // Define what happens when the request completes
  25:      xhr.onload = function () {
  26:        if (xhr.status === 200) {
  27:          // Create a Blob from the response
  28:          const blob = xhr.response;
  29:   
  30:          // Create an object URL for the Blob
  31:          const imageUrl = URL.createObjectURL(blob);
  32:   
  33:          // Create an <img> element and set its src to the object URL
  34:          const img = document.createElement('img');
  35:          img.src = imageUrl;
  36:          img.alt = 'Loaded Image';
  37:   
  38:          // Append the image to the container
  39:          const container = document.getElementById('image-container');
  40:          container.appendChild(img);
  41:   
  42:          // Clean up the object URL when the image is loaded
  43:          img.onload = function () {
  44:            URL.revokeObjectURL(imageUrl);
  45:          };
  46:        } else {
  47:          console.error('Failed to load image. Status:', xhr.status);
  48:        }
  49:      };
  50:   
  51:      // Define what happens if there's an error
  52:      xhr.onerror = function () {
  53:        console.error('An error occurred while loading the image.');
  54:      };
  55:   
  56:      // Send the request
  57:      xhr.send();
  58:    </script>
  59:  </body>
  60:  </html>

2. Require Image with Axios.

https://github.com/AAlex-11/ImageAsync/blob/main/Html/Axios.htm


   1:  <!DOCTYPE html>
   2:  <html lang="en">
   3:  <head>
   4:    <meta charset="UTF-8">
   5:    <meta name="viewport" content="width=device-width, initial-scale=1.0">
   6:    <title>Load Image with Axios</title>
   7:    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
   8:  </head>
   9:  <body>
  10:    <h1>Image Loaded with Axios</h1>
  11:    <div id="image-container">
  12:      <!-- The image will be inserted here -->
  13:    </div>
  14:   
  15:    <script>
  16:      // URL of the image to load
  17:      const imageUrl = 'http://localhost:3000/images/Frontend.png';
  18:   
  19:      // Use Axios to load the image
  20:      axios.get(imageUrl, { responseType: 'blob' })
  21:        .then(response => {
  22:          // Create an object URL for the Blob
  23:          const imageUrl = URL.createObjectURL(response.data);
  24:   
  25:          // Create an <img> element and set its src to the object URL
  26:          const img = document.createElement('img');
  27:          img.src = imageUrl;
  28:          img.alt = 'Loaded Image';
  29:   
  30:          // Append the image to the container
  31:          const container = document.getElementById('image-container');
  32:          container.appendChild(img);
  33:   
  34:          // Clean up the object URL when the image is loaded
  35:          img.onload = function () {
  36:            URL.revokeObjectURL(imageUrl);
  37:          };
  38:        })
  39:        .catch(error => {
  40:          console.error('Error loading image:', error);
  41:        });
  42:    </script>
  43:  </body>
  44:  </html>

3. jQuery Ajax ($.ajax).


https://github.com/AAlex-11/ImageAsync/blob/main/Html/Ajax1.htm


   1:  <!DOCTYPE html>
   2:  <html lang="en">
   3:  <head>
   4:      <meta charset="UTF-8">
   5:      <meta name="viewport" content="width=device-width, initial-scale=1.0">
   6:      <title>Load Image with jQuery AJAX</title>
   7:      <!-- Include jQuery -->
   8:      <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
   9:  </head>
  10:  <body>
  11:  <div id="image-container">
  12:      <!-- The image will be inserted here -->
  13:  </div>
  14:   
  15:  <script>
  16:      // URL of the image to load
  17:      const imageUrl = 'http://localhost:3000/images/Frontend.png';
  18:   
  19:      // Use jQuery AJAX to load the image
  20:      $.ajax({
  21:          url: imageUrl,
  22:          method: 'GET',
  23:          xhrFields: {
  24:              responseType: 'blob' // Set the response type to Blob
  25:          },
  26:          success: function (blob) {
  27:              // Create an object URL for the Blob
  28:              const imageUrl = URL.createObjectURL(blob);
  29:   
  30:              // Create an <img> element and set its src to the object URL
  31:              const img = $('<img>', {
  32:                  src: imageUrl,
  33:                  alt: 'Loaded Image'
  34:              });
  35:   
  36:              // Append the image to the container
  37:              $('#image-container').append(img);
  38:   
  39:              // Clean up the object URL when the image is loaded
  40:              img.on('load', function () {
  41:                  URL.revokeObjectURL(imageUrl);
  42:              });
  43:          },
  44:          error: function (xhr, status, error) {
  45:              console.error('Error loading image:', error);
  46:          }
  47:      });
  48:  </script>
  49:  </body>
  50:  </html>


4. jQuery Ajax ($.get).

https://github.com/AAlex-11/ImageAsync/blob/main/Html/Ajax2.htm


   1:  <!DOCTYPE html>
   2:  <html lang="en">
   3:  <head>
   4:      <meta charset="UTF-8">
   5:      <meta name="viewport" content="width=device-width, initial-scale=1.0">
   6:      <title>Load Image with jQuery $.get()</title>
   7:      <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
   8:  </head>
   9:  <body>
  10:  <div id="image-container">
  11:      <!-- The image will be inserted here -->
  12:  </div>
  13:   
  14:  <script>
  15:      // Configure jQuery to handle binary data for all $.get requests
  16:      $.ajaxSetup({
  17:          xhrFields: {
  18:              responseType: 'blob' // Set the response type to Blob
  19:          }
  20:      });
  21:   
  22:      // URL of the image to load
  23:      const imageUrl = 'http://localhost:3000/images/Frontend.png';
  24:   
  25:      // Use jQuery $.get() to load the image
  26:      $.get(imageUrl, function (blob) {
  27:          // Create an object URL for the Blob
  28:          const imageUrl = URL.createObjectURL(blob);
  29:   
  30:          // Create an <img> element and set its src to the object URL
  31:          const img = $('<img>', {
  32:              src: imageUrl,
  33:              alt: 'Loaded Image'
  34:          });
  35:   
  36:          // Append the image to the container
  37:          $('#image-container').append(img);
  38:   
  39:          // Clean up the object URL when the image is loaded
  40:          img.on('load', function () {
  41:              URL.revokeObjectURL(imageUrl);
  42:          });
  43:      }).fail(function (xhr, status, error) {
  44:          console.error('Error loading image:', error);
  45:      });
  46:  </script>
  47:  </body>
  48:  </html>


5. Lazy Loaded attribute

https://github.com/AAlex-11/ImageAsync/blob/main/Html/Lazy1.htm


   1:  <!doctype html>
   2:  <html lang="en">
   3:  <head>
   4:      <meta charset="UTF-8">
   5:      <meta name="viewport" content="width=device-width, initial-scale=1">
   6:      <title>Document</title>
   7:  </head>
   8:   
   9:  <body>
  10:      <img src="http://localhost:3000/images/Frontend.png" alt="Lazy Loaded Image" loading="lazy">
  11:      <script>
  12:          const img = document.querySelector('img');
  13:          img.onload = function () {
  14:              console.log('Image loaded');
  15:          };
  16:          img.onerror = function () {
  17:              console.error('Image failed to load');
  18:          };
  19:      </script>
  20:  </body>
  21:  </html>

Or


https://github.com/AAlex-11/ImageAsync/blob/main/Html/Lazy2.htm


   1:  <!DOCTYPE html>
   2:  <html lang="en">
   3:  <head>
   4:      <meta charset="UTF-8">
   5:      <meta name="viewport" content="width=device-width, initial-scale=1">
   6:      <title>Document</title>
   7:      <script>
   8:          // Wait for the entire page to load
   9:          window.onload = function () {
  10:              // Select the <img> element from the DOM
  11:              const img = document.querySelector('img');
  12:   
  13:              // Add event listeners for load and error
  14:              img.onload = function () {
  15:                  console.log('Image loaded');
  16:              };
  17:              img.onerror = function () {
  18:                  console.error('Image failed to load');
  19:              };
  20:          };
  21:      </script>
  22:  </head>
  23:  <body>
  24:  <img src="http://localhost:3000/images/Frontend.png" alt="Lazy Loaded Image" loading="lazy">
  25:  </body>


6. Angular Async Pipe to load images asynchronously.

6.1. Angular project start.

    # npm install -g @angular/cli
    # ng new image-loader-app
    # cd image-loader-app
    # ng update @angular/core@19 @angular/cli@19
    # npm install @angular/common@latest rxjs@latest --save
    # ng generate component image-loader

6.2. Project template.



In all next Angular projects I will use Angular template with lazy loading with small deviation:


   1:  <div *ngIf="imageUrl$ | async as imageUrl; else loading">
   2:    <img [src]="imageUrl" alt="Loaded Image">
   3:    <p>Image loaded successfully!</p>
   4:  </div>
   5:  <ng-template #loading>
   6:    <div class="spinner"></div>
   7:  </ng-template>
   8:  <div *ngIf="errorMessage">
   9:    <p style="color: red;">{{ errorMessage }}</p>
  10:  </div>
  11:  <button (click)="loadImage()">Refresh Image</button>

I will use this image server for next project templates https://github.com/AAlex-11/ImageAsync/tree/main/ImageServer

6.3. Common Angular features.

Firstly let's remember Angular syntax and features:

  • Angular syntax:
    • Angular Async pipe "|" - a built-in pipe that's used to automatically subscribe to an Observable and automatic updates when new data arrives
    • (click) - Round brackets denote event binding (e.g., (click)="loadImage()").
    • [src] - Square brackets denote property binding.
    • {{ }} - Curly brackets denote interpolation (e.g., {{ errorMessage }}).
    • ng-template, *ngIf, # - other basic Angular features
  • Standalone Components:
    • Don't need NgModule.ts bundle
    • Imports need in component declarations, something like this (e.g., setTimeout, Promise, XMLHttpRequest) to trigger change detection
  • What is Zone.js:
    • Wrapper around asynchronous operations
    • Sometimes automatic detect changing don't working we need applying changing on View manually with Zone.js
    • provideZoneChangeDetection({ eventCoalescing: true }) - provide detection of multiple events into a single change detection cycle
  • Angular config provide various tuning, for example
    • extract-i18n Extracts internationalization (i18n) messages from the application for translation
  • environment.ts
    • Provide application level parameters

6.4. More details about Observable and Promise.

Angular can worki with Observable from RxJS or with JS Promise.:

  • Promise - Represents a single value that will be available in the future. Observable - Represents a stream of values over time. Observable as a stream of Promises.
  • The $ suffix is a naming convention for Observable variables. After unwrapping the Observable with async, the emitted value is assigned to imageUrl. imageUrl is a plain string.

JS Promise:

  • Single Value. A Promise represents a single asynchronous value that will be resolved or rejected in the future.
  • Eager Execution. A Promise starts executing as soon as it is created.
  • Non-Cancellable. Once a Promise is created, it cannot be canceled.
  • Then. and Catch Access to feature Promise value make with .then(), .catch() get exception.

  •    1:  const promise = new Promise((resolve, reject) => {
       2:    setTimeout(() => resolve('Data loaded!'), 1000);
       3:  });
       4:   
       5:  promise.then(result => console.log(result)); // Output: "Data loaded!"

RxJS Observable (More about RxJS):

  • Stream of Values. An Observable represents a stream of values over time. It can emit zero, one, or multiple values.
  • Lazy Execution. An Observable does not start executing until it is subscribed to.
  • Cancellable. You can cancel an Observable subscription using the unsubscribe() method

  •    1:  import { Observable } from 'rxjs';
       2:   
       3:  const observable = new Observable(observer => {
       4:    setTimeout(() => observer.next('Data 1'), 1000);
       5:    setTimeout(() => observer.next('Data 2'), 2000);
       6:    setTimeout(() => observer.complete(), 3000);
       7:  });
       8:   
       9:  const subscription = observable.subscribe({
      10:    next: value => console.log(value), // Output: "Data 1", "Data 2"
      11:    complete: () => console.log('Completed!'), // Output: "Completed!"
      12:  });
      13:   
      14:  // Unsubscribe after 2.5 seconds
      15:  setTimeout(() => subscription.unsubscribe(), 2500);

  • And more details about Observable, Various RxJS methods and operators applied to Observable:
    • map - Transforms the emitted value (e.g., converting a Blob to a URL).
    • tap - Used for side effects (e.g., logging, updating variables)
    • Subject - special type of Observable that can both emit values and be subscribed to
    • switchMap - operator is used to map each emission of reload$ to a new HTTP request. This ensures that only the latest request is active, preventing multiple overlapping requests.
    • of - Converts the arguments to an observable sequence

6.5. Angular Async pipe Promise template.

https://github.com/AAlex-11/ImageAsync/tree/main/AngularAsyncPipe5


   1:  import { Component } from '@angular/core';
   2:  import { HttpClient } from '@angular/common/http';
   3:  import { AsyncPipe, CommonModule } from '@angular/common';
   4:  import { environment } from '../../environment';
   5:  import { firstValueFrom } from 'rxjs'; // Import firstValueFrom
   6:  
   7:  @Component({
   8:    selector: 'app-image-loader',
   9:    standalone: true,
  10:    imports: [AsyncPipe, CommonModule],
  11:    templateUrl: './image-loader.component.html',
  12:  })
  13:  export class ImageLoaderComponent {
  14:    imageUrlPromise: Promise<string | null>; // Use a Promise
  15:    errorMessage: string | null = null;
  16:  
  17:    constructor(private http: HttpClient) {
  18:      this.imageUrlPromise = this.loadImage();
  19:    }
  20:  
  21:    // Method to load the image using Promises
  22:    async loadImage(): Promise<string | null> {
  23:      try {
  24:        // firstValueFrom is a new alternatives to toPromise()
  25:        const blob = await firstValueFrom(this.http.get(environment.imageUrl, { responseType: 'blob' }));
  26:        console.log('Received Blob:', blob); // Log the Blob
  27:  
  28:        // Ensure blob is defined before creating the URL
  29:        if (blob) {
  30:          return URL.createObjectURL(blob); // Convert Blob to URL and return
  31:        } else {
  32:          throw new Error('Blob is undefined');
  33:        }
  34:      } catch (error) {
  35:        console.error('Error loading image:', error);
  36:        this.errorMessage = 'Failed to load image. Please try again later.';
  37:        return null;
  38:      }
  39:    }
  40:  }
  41:  
  42:  

   1:  <div *ngIf="imageUrlPromise | async as imageUrl; else loading">
   2:    <img [src]="imageUrl" alt="Loaded Image">
   3:    <p>Image loaded successfully!</p>
   4:  </div>
   5:  <ng-template #loading>
   6:    <div class="spinner"></div>
   7:  </ng-template>
   8:  <div *ngIf="errorMessage">
   9:    <p style="color: red;">{{ errorMessage }}</p>
  10:  </div>
  11:   

6.6. Angular Async pipe Observable template.

https://github.com/AAlex-11/ImageAsync/tree/main/AngularAsyncPipe1


   1:  import { Component } from '@angular/core';
   2:  import { HttpClient } from '@angular/common/http';
   3:  import { AsyncPipe, CommonModule } from '@angular/common';
   4:  import { catchError, Observable, of, tap} from 'rxjs';
   5:  import { map } from 'rxjs/operators';
   6:  import { environment } from '../../environment'
   7:  
   8:  @Component({
   9:    selector: 'app-image-loader',
  10:    standalone: true, // Mark as standalone
  11:    imports: [AsyncPipe, CommonModule],
  12:    templateUrl: './image-loader.component.html'
  13:  })
  14:  export class ImageLoaderComponent {
  15:    imageUrl$: Observable<string | null>;
  16:    errorMessage: string | null = null;
  17:  
  18:    constructor(private http: HttpClient) {
  19:      this.imageUrl$ = this.http.get(environment.imageUrl, { responseType: 'blob' })
  20:        .pipe(
  21:          tap(blob => console.log('Received Blob:', blob)), // Log the Blob
  22:          map(blob => URL.createObjectURL(blob)), // Convert Blob to URL
  23:          tap(url => console.log('Generated URL:', url)), // Log the generated URL
  24:          catchError(error => {
  25:            console.error('Error loading image:', error);
  26:            this.errorMessage = 'Failed to load image. Please try again later.';
  27:            return of(null);
  28:          })
  29:      );
  30:    }
  31:  }
  32:  

   1:  <div *ngIf="imageUrl$ | async as imageUrl; else loading">
   2:    <img [src]="imageUrl" alt="Loaded Image">
   3:    <p>Image loaded successfully!</p>
   4:  </div>
   5:  <ng-template #loading>
   6:    <div class="spinner"></div>
   7:  </ng-template>
   8:  <div *ngIf="errorMessage">
   9:    <p style="color: red;">{{ errorMessage }}</p>
  10:  </div>
  11:   

6.7. Angular Async pipe Observable template with Refresh button and Subject.

https://github.com/AAlex-11/ImageAsync/tree/main/AngularAsyncPipe2


   1:  import { Component } from '@angular/core';
   2:  import { HttpClient } from '@angular/common/http';
   3:  import { AsyncPipe, CommonModule } from '@angular/common';
   4:  import { Observable, of, Subject} from 'rxjs';
   5:  import { catchError, map, switchMap, tap } from 'rxjs/operators';
   6:  import { environment } from '../../environment'
   7:  
   8:  @Component({
   9:    selector: 'app-image-loader',
  10:    standalone: true, // Mark as standalone
  11:    imports: [AsyncPipe, CommonModule],
  12:    templateUrl: './image-loader.component.html'
  13:  })
  14:  export class ImageLoaderComponent {
  15:    imageUrl$: Observable<string | null>;
  16:    errorMessage: string | null = null;
  17:    private reload$ = new Subject<void>();// Subject to trigger reloads
  18:  
  19:    constructor(private http: HttpClient) {
  20:      this.imageUrl$ = this.reload$.pipe(
  21:        switchMap(() => this.http.get(environment.imageUrl, { responseType: 'blob' })
  22:        .pipe(
  23:          tap(blob => console.log('Received Blob:', blob)), // Log the Blob
  24:          map(blob => URL.createObjectURL(blob)), // Convert Blob to URL
  25:          tap(url => console.log('Generated URL:', url)), // Log the generated URL
  26:          catchError(error => {
  27:            console.error('Error loading image:', error);
  28:            this.errorMessage = 'Failed to load image. Please try again later.';
  29:            return of(null);
  30:          })
  31:        ))
  32:      );
  33:      // Trigger the first load
  34:      this.loadImage();
  35:    }
  36:  
  37:    // Method to trigger a reload
  38:    loadImage() {
  39:      this.errorMessage = null; // Clear any previous error message
  40:      this.reload$.next(); // Emit a value to trigger the reload
  41:    }
  42:  }
  43:  

   1:  <div *ngIf="imageUrl$ | async as imageUrl; else loading">
   2:    <img [src]="imageUrl" alt="Loaded Image">
   3:    <p>Image loaded successfully!</p>
   4:  </div>
   5:  <ng-template #loading>
   6:    <div class="spinner"></div>
   7:  </ng-template>
   8:  <div *ngIf="errorMessage">
   9:    <p style="color: red;">{{ errorMessage }}</p>
  10:  </div>
  11:  <button (click)="loadImage()">Refresh Image</button>
  12:   

6.8. Angular Async pipe templates with XMLHttpRequest

https://github.com/AAlex-11/ImageAsync/tree/main/AngularAsyncPipe3


   1:  import { Component } from '@angular/core';
   2:  import { AsyncPipe, CommonModule } from '@angular/common';
   3:  import { Observable, Subject, of } from 'rxjs';
   4:  import { catchError, map, switchMap, tap } from 'rxjs/operators';
   5:  import { environment } from '../../environment'
   6:  
   7:  @Component({
   8:    selector: 'app-image-loader',
   9:    standalone: true,
  10:    imports: [AsyncPipe, CommonModule],
  11:    templateUrl: './image-loader.component.html',
  12:  })
  13:  export class ImageLoaderComponent {
  14:    imageUrl$: Observable<string | null>;
  15:    errorMessage: string | null = null;
  16:    private reload$ = new Subject<void>(); // Subject to trigger reloads
  17:  
  18:    constructor() {
  19:      this.imageUrl$ = this.reload$.pipe(
  20:        switchMap(() => this.loadImageWithXHR()), // Use XMLHttpRequest to load the image
  21:        catchError(error => {
  22:          console.error('Error loading image:', error);
  23:          this.errorMessage = 'Failed to load image. Please try again later.';
  24:          return of(null); // Return null in case of an error
  25:        })
  26:      );
  27:      // Trigger the first load
  28:      this.loadImage();
  29:    }
  30:  
  31:    // Method to trigger a reload
  32:    loadImage() {
  33:      this.errorMessage = null; // Clear any previous error message
  34:      this.reload$.next(); // Emit a value to trigger the reload
  35:    }
  36:  
  37:    // Method to load an image using XMLHttpRequest
  38:    private loadImageWithXHR(): Observable<string> {
  39:      return new Observable(observer => {
  40:        const xhr = new XMLHttpRequest();
  41:        xhr.open('GET', environment.imageUrl, true);
  42:        xhr.responseType = 'blob'; // Set the response type to blob
  43:        xhr.onload = () => {
  44:          if (xhr.status === 200) {
  45:            const blob = xhr.response;
  46:            const imageUrl = URL.createObjectURL(blob); // Convert Blob to URL
  47:            observer.next(imageUrl); // Emit the image URL
  48:            observer.complete(); // Complete the observable
  49:          } else {
  50:            observer.error(new Error(`Failed to load image. Status: ${xhr.status}`));
  51:          }
  52:        };
  53:        xhr.onerror = () => {
  54:          observer.error(new Error('Network error while loading image.'));
  55:        };
  56:        xhr.send(); // Send the request
  57:      });
  58:    }
  59:  }
  60:  

   1:  <div *ngIf="imageUrl$ | async as imageUrl; else loading">
   2:    <img [src]="imageUrl" alt="Loaded Image">
   3:    <p>Image loaded successfully!</p>
   4:  </div>
   5:  <ng-template #loading>
   6:    <div class="spinner"></div>
   7:  </ng-template>
   8:  <div *ngIf="errorMessage">
   9:    <p style="color: red;">{{ errorMessage }}</p>
  10:  </div>
  11:  <button (click)="loadImage()">Refresh Image</button>
  12:   

6.9. Angular feature - list of app-image-loader components

https://github.com/AAlex-11/ImageAsync/tree/main/AngularAsyncPipe4


   1:  import { Component } from '@angular/core';
   2:  import { ImageLoaderComponent } from '../image-loader/image-loader.component';
   3:  import { CommonModule } from '@angular/common';
   4:  
   5:  @Component({
   6:    selector: 'app-image-list',
   7:    standalone: true,
   8:    imports: [CommonModule,ImageLoaderComponent],
   9:    templateUrl: './image-list.component.html',
  10:    styleUrls: ['./image-list.component.css'],
  11:  })
  12:  export class ImageListComponent {
  13:    // Define an array of image URLs
  14:    imageUrls: string[] = [
  15:      'http://localhost:3000/images/image1.png',
  16:      'http://localhost:3000/images/image2.png',
  17:      'http://localhost:3000/images/image3.png',
  18:      'http://localhost:3000/images/image4.png',
  19:      'http://localhost:3000/images/image5.png',
  20:      'http://localhost:3000/images/image6.png',
  21:      'http://localhost:3000/images/image7.png',
  22:      'http://localhost:3000/images/image8.png',
  23:      'http://localhost:3000/images/image9.png',
  24:      'http://localhost:3000/images/image10.png',
  25:    ];
  26:  }
  27:  
   1:  <div class="image-list">
   2:    <app-image-loader *ngFor="let url of imageUrls" [imageUrl]="url"></app-image-loader>
   3:  </div>

6.10. Convert Angular component to service.

# ng generate service services/image-loader

https://github.com/AAlex-11/ImageAsync/tree/main/AngularAsyncPipe6


   1:  // src/app/services/image-loader.service.ts
   2:  import { Injectable } from '@angular/core';
   3:  import { HttpClient } from '@angular/common/http';
   4:  import { Observable, of } from 'rxjs';
   5:  import { catchError, map, tap } from 'rxjs/operators';
   6:  import { environment } from '../../environment';
   7:  
   8:  @Injectable({
   9:    providedIn: 'root', // Make the service available application-wide
  10:  })
  11:  export class ImageLoaderService {
  12:    constructor(private http: HttpClient) {}
  13:  
  14:    // Method to load an image and return an Observable
  15:    loadImage(imageUrl: string): Observable<string | null> {
  16:      return this.http.get(imageUrl, { responseType: 'blob' }).pipe(
  17:        tap(blob => console.log('Received Blob:', blob)), // Log the Blob
  18:        map(blob => URL.createObjectURL(blob)), // Convert Blob to URL
  19:        tap(url => console.log('Generated URL:', url)), // Log the generated URL
  20:        catchError(error => {
  21:          console.error('Error loading image:', error);
  22:          return of(null);
  23:        })
  24:      );
  25:    }
  26:  }
  27:  

   1:  import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';
   2:  import { AsyncPipe, CommonModule } from '@angular/common';
   3:  import { Observable } from 'rxjs';
   4:  import { ImageLoaderService } from '../services/image-loader.service';
   5:  
   6:  @Component({
   7:    selector: 'app-image-loader',
   8:    standalone: true,
   9:    imports: [AsyncPipe, CommonModule],
  10:    templateUrl: './image-loader.component.html',
  11:  })
  12:  export class ImageLoaderComponent implements OnInit {
  13:    @Input() imageUrl: string = ''; // Accept an input for the image URL
  14:    imageUrl$: Observable<string | null> | null = null;
  15:    errorMessage: string | null = null;
  16:  
  17:    constructor(private imageLoaderService: ImageLoaderService) {}
  18:  
  19:    ngOnInit() {
  20:      this.imageUrl$ = this.imageLoaderService.loadImage(this.imageUrl);
  21:    }
  22:  }
  23:  



Browser context:



Angular context:



FrontLearning context:



Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23>  <24>  <25
Link to this page: http://www.vb-net.com/ImagesAsync/Index.htm
<TAGS>  <ARTICLES>  <FRONT>  <CORE>  <MVC>  <ASP>  <NET>  <DATA>  <TASK>  <XML>  <KIOSK>  <NOTES>  <SQL>  <LINUX>  <MONO>  <FREEWARE>  <DOCS> <TRAVELS> <FLOWERS> <RESUME> < THANKS ME>