How to cache images in Angular

Gaurav Soni
3 min readAug 20, 2019

--

Photo by Murray Campbell on Unsplash

In this article, we will see how we can cache images in angular so that we can load them faster. let’s get started.
First, we need to create a new angular service. We can create it angular CLI,

ng g s image

it will create,

import { Injectable } from ‘@angular/core’;@Injectable()
export class ImageService {
constructor() { }}

The first thing we need to create is an empty array of URLs that needs to be cached,

private _cacheUrls: string[] = [];

We also need to create an empty array of cachedImages of CachedImage interface,

interface CachedImage {
url: string;
blob: Blob;
}
private _cachedImages: CachedImage[] = [];

We are making the arrays private but we can access them by creating getters and setters. We will create below setters and getters for the array,

set cacheUrls(urls: string[]) {
this._cacheUrls = […urls];
}
get cacheUrls(): string[] {
return this._cacheUrls;
}
set cachedImages(image: CachedImage) {
this._cachedImages.push(image);
}

After this, our service will look like,

import { Injectable } from ‘@angular/core’;interface CachedImage {
url: string;
blob: Blob;
}
@Injectable({
providedIn: ‘root’
})
export class ImageService {
private _cacheUrls: string[] = [];
private _cachedImages: CachedImage[] = [];
constructor() { }set cacheUrls(urls: string[]) {
this._cacheUrls = […urls];
}
get cacheUrls(): string[] {
return this._cacheUrls;
}
set cachedImages(image: CachedImage) {
this._cachedImages.push(image);
}
}

Now we need to create the main method of the service that will return either cached image or fetch it over the network. So the method will look like,

constructor(private http: HttpClient) { }
getImage(url: string) {
const index = this._cachedImages.findIndex(image => image.url === url);
if (index > -1) {
const image = this._cachedImages[index];
return of(URL.createObjectURL(image.blob));
}
return this.http.get(url, { responseType: ‘blob’ }).pipe(
tap(blob => this.checkAndCacheImage(url, blob))
);
}

Note: For using httpClient, We need to import HttpClientModule.

Let’s look at the method.
Here first we are finding the index of URL in cachedImages array. If the index is greater than -1 that means image exists in the array, we are converting the blob into URL and returning the observable of that URL. We are returning the observable so that in the component we can use the subscribe method for both cached and uncached images.

If the image doesn’t exist in the cachedImages array, we are fetching the image by using angular HttpClient. We are using tap operator to interfere with the observable and caching the image. The checkAndCacheImage method will look like below:-

checkAndCacheImage(url: string, blob: Blob) {
if (this._cacheUrls.indexOf(url) > -1) {
this._cachedImages.push({url, blob});
}
}

Here we are simply checking if the URL exists in the images that need to be cached. If exist then we are putting them into cachedImages array.

Now we are ready to use. In your components ngOnInit lifecycle hook we can use it like below,

@Component({
selector: ‘my-app’,
templateUrl: ‘./app.component.html’,
styleUrls: [‘./app.component.css’]
})
export class AppComponent implements OnInit {
@ViewChild(‘img’, { static: true }) image: ElementRef;
@ViewChild(‘newImg’, { static: true }) newImage: ElementRef;
constructor(private imageService: ImageService) {
}
ngOnInit() {
const url = ‘https://picsum.photos/id/237/200/300';
this.imageService.cacheUrls = [url];
this.imageService.getImage(url).subscribe(res => {
console.log(res);
this.image.nativeElement.src = url;
});
}
}

In your app.component.html,

<img #img />

Now suppose we want to use the same image again we can call the same method again but this time we will cached image which will be loaded faster.

For example in app.component.html,

<button (click)=”loadImage()”>Load Image</button>

In app.component.ts,

loadImage() {
const url = ‘https://picsum.photos/id/237/200/300';
this.imageService.getImage(url).subscribe(res => {
this.newImage.nativeElement.src = res;
});
}

So this is the simple way to cache images. Since angular services are singleton by default. We can use this feature to share cached images through out the app.

--

--