web-dev-qa-db-fra.com

Comment afficher une image d'espace réservé avant le chargement de l'image réelle dans une application Ionic 2 ou 3

Bonne journée,

Je travaille sur une application Ionic et je charge des images dynamiquement à partir d'un flux JSON. J'aimerais que lorsque les images soient extraites de l'URL externe dans laquelle une image d'espace réservé s'affiche. sa place, par la suite, l'image d'espace réservé doit alors être remplacée par l'image "réelle" une fois chargée.

Un exemple de ma situation actuelle est:

<ion-card *ngFor="let item of items"...
 <img [src]="item.picture" />

Merci et salutations.

12
TC Roberts

Pouvez-vous modifier votre JSON pour avoir une propriété booléenne loaded? Si vous le pouvez, ce sera facile, procédez comme suit:

<ion-card *ngFor="let item of items">
  <img [src]="item.picture" (load)="item.loaded = true" [hidden]="!item.loaded" />
  <img src="../path/to/your/placeholer/image.jpg" [hidden]="item.loaded">
</ion-card>

Vous aurez une propriété chargée toujours initalisée en tant que false, lorsque l'image se charge, l'événement (load) Sera déclenché et changera la propriété d'image chargée en true, en cachant l'image d'espace réservé et en montrant l'imagem chargé .

Si vous ne pouvez pas modifier ce JSON (ou s'il est trop gros pour être modifié), vous pouvez utiliser le code ci-dessus, mais procédez comme suit dans votre page .ts

public functionWhoseIsLoadingYourJson(){
  // HTTP REQUEST FOR JSON
  .subscribe(response => {
    response.forEach(element => {
      element.loaded = false;
    });
    this.items = response;
  });
}

Itérez simplement votre réponse et dans chaque objet définissez une propriété chargée sur false. Si cela génère une erreur, vous pouvez mettre votre <ion-card> Dans un div avec un * ngIf

<div *ngIf="this.items != null">
  <!-- ion card -->
</div>

EDIT - Mise à jour de JSON

Comme il vient de Firebase, il existe trois options pour mettre à jour votre JSON. La première est une fonction que vous exécuteriez une seule fois pour mettre à jour votre base de données, la seconde est toujours le code que j'ai donné (en parcourant les résultats et en poussant la valeur booléenne) mais ce sera différent puisque vous utilisez Firebase.

Première solution:

Quelque part dans votre code, il peut s'agir de n'importe quelle page, il vous suffit de l'exécuter une fois:

firebase.database().ref('myDataNode').on('value', snapshot => {
  for(let key in snapshot.val()){
    firebase.database().ref('myDataNode/' + key + '/loaded').set(false);
  }
});

Assurez-vous que je passe en revue tous les résultats de votre myDataNode et que j'utilise leur clé pour définir une propriété loaded sur false. Mais faites attention lorsque vous utilisez set puisque vous pouvez remplacer tous vos nœuds, avant de faire cette méthode, n'oubliez pas d'exporter votre nœud Firebase pour avoir une sauvegarde. Et si vous transférez vos images vers Firebase de n'importe où dans votre code, n'oubliez pas de le modifier pour définir ensemble une propriété loaded.

Le deuxième, comme mentionné, est ce que j'ai fait dans cette réponse, mais maintenant en l'utilisant dans votre appel Firebase et en utilisant la méthode forEach fournie avec l'instantané:

firebase.database().ref('myDataNode').on('value', snapshot => {
  snapshot.forEach(element =>{
    this.myDataNode.Push({
      picture: element.val(), // maybe it needs to be element.val().nameOfYourProperty
      loaded: false
    })
  });
});

Cela va pousser un nouvel élément dans votre tableau avec l'URL de l'image et la propriété chargée. S'il ne peut pas reconnaître la méthode .Push(), déclarez simplement votre variable tapée sous forme de tableau:

public myDataNode: any[];

Le troisième est juste une mise à jour locale, faites une itération via votre snapshot Firebase, enregistrez le résultat dans une variable locale, créez une nouvelle propriété et poussez-la dans votre tableau:

firebase.database().ref('myDataNode').on('value', snapshot => {
  for (let key in snapshot.val()){
    snapshot.forEach(item => { // iterate snapshot
      let record = item.val(); // save the snapshot item value in a local variable
      record.loaded = true; // add the property
      this.newArray.Push(record); // Push it to your array that'll  be used in ng-for
      return true; // return true to foreach
    });
  }
});

J'espère que cela t'aides.

1
Gabriel Barreto

La plupart des réponses concernent l'ajout de la logique du chèque chargé dans la même vue, mais cela ne semble pas approprié. Au lieu de cela, vous pouvez créer votre propre directive qui s'en occupera. Vous pouvez jeter un oeil à cet article étonnant pour voir comment cela peut être fait.

Première copie ce GIF dans votre src/assets dossier, et nommez-le preloader.gif.

Ajoutez ensuite cette directive personnalisée. Le code est assez explicite:

// 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;
  }

}

Ajoutez ensuite la nouvelle directive à votre module d'application, comme ceci:

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 {}

Voici comment vous pouvez utiliser votre nouvelle directive personnalisée:

<img img-preloader="https://images.unsplash.com/photo-1413781892741-08a142b23dfe" alt="">

Et voici à quoi cela ressemblera:

Result

Vous pouvez ensuite définir la hauteur/largeur du conteneur de l'image, de sorte que le gif du préchargeur et l'image finale aient les mêmes dimensions.

20
sebaferreras

J'espère que vous pourrez essayer comme indiqué ci-dessous. Vous pouvez stocker votre image d'espace réservé dans le assets/images dossier.

. html

<ion-card *ngFor="let item of items">
 <img [src]="item?.picture!= null ? item.picture : myImgUrl" />
</ion-card>

. ts

export class MyPage{
   myImgUrl:stirng='./assets/images/myimage.png;

   constructor(){}
}
0
Sampath

Pour autant que je sache, il n'y a pas Ionic moyen de le faire. Mais vous pouvez toujours le faire par javascript et css.

Manière CSS:

Créez une div div couvrir votre image et définissez l'image d'espace réservé est background-image de cette div.

<div class="image">
    <img src="your_main_image"/>
</div>
.image{
    background-image: url('your_placeholder_image');
}

Manière Javascript:

Il existe plusieurs méthodes par javascript que vous pouvez facilement trouver dans stackoverflow donc je ne répondrai pas ici. Celui-ci est un exemple

0
Duannx