Good day,
I'm working on an Ionic application and I'm loading images dynamically from a JSON feed. I would like that when the images are being pulled in from the external URL that a placeholder image shows in its place, thereafter, the placeholder image should then be replaced by the "real" image once its loaded.
An example of my current situation is:
<ion-card *ngFor="let item of items"...
<img [src]="item.picture" />
Thanks & Regards.
Most of the answers are about adding the logic of the loaded check in the same view, but it seems not appropriate. Instead, you can create your own directive that will take care of it. You can take a look at this amazing article to see how it can be done.
First copy this GIF in your src/assets
folder, and name it preloader.gif
.
Then add this custom directive. The code is pretty much self-explanatory:
// An image directive based on http://blog.teamtreehouse.com/learn-asynchronous-image-loading-javascript
import {Directive, Input, OnInit} from '@angular/core';
// Define the Directive meta data
@Directive({
selector: '[img-preloader]', //E.g <img mg-img-preloader="http://some_remote_image_url"
host: {
'[attr.src]': 'finalImage' //the attribute of the host element we want to update. in this case, <img 'src' />
}
})
//Class must implement OnInit for @Input()
export class ImagePreloader implements OnInit {
@Input('img-preloader') targetSource: string;
downloadingImage : any; // In class holder of remote image
finalImage: any; //property bound to our host attribute.
// Set an input so the directive can set a default image.
@Input() defaultImage : string = 'assets/preloader.gif';
//ngOnInit is needed to access the @inputs() variables. these aren't available on constructor()
ngOnInit() {
//First set the final image to some default image while we prepare our preloader:
this.finalImage = this.defaultImage;
this.downloadingImage = new Image(); // create image object
this.downloadingImage.onload = () => { //Once image is completed, console.log confirmation and switch our host attribute
console.log('image downloaded');
this.finalImage = this.targetSource; //do the switch 😀
}
// Assign the src to that of some_remote_image_url. Since its an Image Object the
// on assignment from this.targetSource download would start immediately in the background
// and trigger the onload()
this.downloadingImage.src = this.targetSource;
}
}
Then add the new directive to your app module, like this:
import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { ImagePreloader } from '../components/img-preload/img-preload';
@NgModule({
declarations: [
MyApp,
ImagePreloader, // <------- Here!
// ...
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
// ...
],
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
})
export class AppModule {}
This is how you can use your new custom directive:
<img img-preloader="https://images.unsplash.com/photo-1413781892741-08a142b23dfe" alt="">
And this is how it will look like:
You can then set the height/width of the container of the image, so both the preloader gif and the final image have the same dimensions.