Angular 2 - Preload background image?
There are few things that you needed like a http, resolver and a sanitizer. here's a link to that explaining how to implement it from scratch.
So for example you have a request then transforming the returned blob into a safe style for us to able to use it in our style directive
this.http.get('assets/img/bg.jpg', { responseType: 'blob' }).pipe(
map( image => {
const blob: Blob = new Blob([image], { type: 'image/jpeg' });
const imageStyle = `url(${window.URL.createObjectURL(blob)})`;
return this.sanitizer.bypassSecurityTrustStyle(imageStyle);
})
)
This solution leverages what angular and the browser already provide. The image loading is done by the browser and there's no need to mess with any data or the DOM yourself.
I have tested this on Chrome 53 and it's working flawlessly.
This is your element, that's getting its background changed:
<div class="yourBackgroundClass" [style.background-image]="'url(' + imgUrl + ')'"></div>
To prefetch the image, we use an image tag, that is not shown. It'd be good to additionally make its position: absolute
and move it out of the view or make it really tiny, so that it can't interfere with your actual content.
<img [src]="imgPreloadUrl" (load)="imgUrl = imgPreloadUrl" hidden>
Through setting imgPreloadUrl
, the img
's src
is updated by angular and the browser loads the image into the invisible img
tag. Once it's done, onload
fires and we set imgUrl = imgPreloadUrl
. Angular now updates style.background-image
of the actual background and the background image switches immediately, because it's already loaded in the hidden image.
While imgUrl !== imgPreloadUrl
we can show a spinner to indicate loading:
<div class="spinner" *ngIf="imgUrl !== imgPreloadUrl"></div>
test with:
<button (click)="imgPreloadUrl = 'https://upload.wikimedia.org/wikipedia/commons/2/24/Willaerts_Adam_The_Embarkation_of_the_Elector_Palantine_Oil_Canvas-huge.jpg'">test</button>
One way to do it would be to use Blob
to get the image and store it in an img
component, this way you have your hands on the loading process and you can add your loading gif:
@Component({
selector:'loading-image',
template:'<img alt="foo" [src]="src"/>'
})
export class ExampleLoadingImage{
public src:string = "http://example.com/yourInitialImage.png";
constructor(private http:Http){}
generateImage(data: any): void {
this.src = 'http://www.downgraf.com/wp-content/uploads/2014/09/01-progress.gif'; //Just a random loading gif found on google.
this.http.get('http://example.com/mycdn/'+this.data.url+'.jpg')
.subscribe(response => {
let urlCreator = window.URL;
this.src = urlCreator.createObjectURL(response.blob());
});
}
}
N.B: You should type your data parameter, typing is a good way to ensure consistency over your code, any
should only be used as a joker, like Object
in Java
.
Using Image Object ( Plunker Demo ⇗ )
tmpImg: HTMLImageElement; // will be used to load the actual image before showing it
generateImage(data: any){
this.urlImage = 'http://example.com/mycdn/'+ 'loading_GIF_url'; // show loading gif
let loaded = () => { // wait for image to load then replace it with loadingGIF
this.urlImage = 'http://example.com/mycdn/' + this.data.url+'.jpg';
}
// background loading logic
if(this.tmpImg){
this.tmpImg.onload = null; // remove the previous onload event, if registered
}
this.tmpImg = new Image();
this.tmpImg.onload = loaded; // register the onload event
this.tmpImg.src = 'http://example.com/mycdn/'+this.data.url+'.jpg';
}