I am experimenting with httpResource
, I am trying to fetch an image
using the new httpResource
method, but I am not sure how to convert the fetched image render in an img
tag.
Below is a sample of what I am trying to do, I checked the network tab and I can see the image is being fetched, but it is not showing inside the image tag.
Angular.dev - HttpResource Docs
I think I need to convert this to a URL.
@Component({
selector: 'app-root',
imports: [FormsModule, CommonModule],
template: `
<input [(ngModel)]="height" type="number"/>
<input [(ngModel)]="width" type="number"/>
<hr/>
@let imageStatus = imageResource.status();
@if(imageResource.value(); as imageVal) {
<img [src]="imageVal"/>
}
`,
})
export class App {
sanitizer = inject(DomSanitizer);
height = signal<number>(200);
width = signal<number>(300);
rs = ResourceStatus;
imageResource = httpResource(
() => `https://picsum.photos/${this.height()}/${this.width()}`
);
}
If you want to fetch an image, then I think httpResource.blob
will be the best option for fetching the image.
I am choosing blob
because it is the minimal type (Read the data, but do not write) to achieve the functionality What is the difference between an ArrayBuffer and a Blob?
imageResource = httpResource.blob(() => `https://picsum.photos/${this.height()}/${this.width()}`, { ... });
But the HTML element img accepts either a path or a URL to the resource.
So we need to convert this blob
to a url string.
We can then leverage parse
property of the second argument of httpResource
which is a part of httpResourceOptions
, this can be used to transform the fetched blob
into a URL.
sanitizer = inject(DomSanitizer);
height = signal<number>(200);
width = signal<number>(300);
rs = ResourceStatus;
imageResource = httpResource.blob(
() => `https://picsum.photos/${this.height()}/${this.width()}`,
{
parse: (blob: Blob) => {
let image = null;
if (blob) {
let objectURL = URL.createObjectURL(blob);
image = this.sanitizer.bypassSecurityTrustUrl(objectURL);
return objectURL;
}
return image;
},
}
);
We can then use URL: createObjectURL() to convert the blob
to a URL
string.
As an additional safety, we can sanitize the url
using the DomSanitizer
method bypassSecurityTrustUrl
and finally return the safe url.
We can use @switch
along with the resource api
signals:
status
-> status of the resource fetched
value
-> value of the resource fetched
Combine this with ResourceStatus, we can show loading status and error status.
<input [(ngModel)]="height" type="number"/>
<input [(ngModel)]="width" type="number"/>
<hr/>
@let imageStatus = imageResource.status();
@switch(imageStatus) {
@case (rs.Resolved) {
@let image = imageResource.value();
<img [src]="image"/>
}
@case (rs.Error) {
Failed to fetch the image...
}
@default {
Loading...
}
}
import {
Component,
signal,
computed,
ResourceStatus,
inject,
} from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { DomSanitizer } from '@angular/platform-browser';
import {
httpResource,
HttpResourceOptions,
HttpResourceRequest,
provideHttpClient,
} from '@angular/common/http';
import { bootstrapApplication } from '@angular/platform-browser';
@Component({
selector: 'app-root',
imports: [FormsModule, CommonModule],
template: `
<input [(ngModel)]="height" type="number"/>
<input [(ngModel)]="width" type="number"/>
<hr/>
@let imageStatus = imageResource.status();
@switch(imageStatus) {
@case (rs.Resolved) {
@let image = imageResource.value();
<img [src]="image"/>
}
@case (rs.Error) {
Failed to fetch the image...
}
@default {
Loading...
}
}
`,
})
export class App {
sanitizer = inject(DomSanitizer);
height = signal<number>(200);
width = signal<number>(300);
rs = ResourceStatus;
imageResource = httpResource.blob(
() => `https://picsum.photos/${this.height()}/${this.width()}`,
{
parse: (blob: Blob) => {
let image = null;
if (blob) {
let objectURL = URL.createObjectURL(blob);
image = this.sanitizer.bypassSecurityTrustUrl(objectURL);
return objectURL;
}
return image;
},
}
);
}
bootstrapApplication(App, {
providers: [provideHttpClient()],
});