Développement d'une aplication Hybride

F. Hémery

Janvier 2017

1 Application Mobile et HTML

Dans les TP précédents nous avons utilisé le langage java pour écrire des applications à destination de machines équipées du système android. Le travail doit être adapté si la machine cible n'est pas équipée du système android.

Quand c'est possible, on écrira une application web responsive, une application web qui va pouvoir être consultée quel que soit le client. Dans ce cas l'application est affichée par le navigateur de la cible.

Il existe un dernier type de développement à destination de cibles hétérogènes (android, ios, ...), qui l'on nomme applications hybrides. Les applications hybrides sont écrites en utilisant le langage du web (html, css, javascript). Elles sont compilées en spécifiant le système cible (android, ios, ...). Cette étape permet d'améliorer l'efficacité de l'application, de s'approcher du thème spécifique de chaque cible et permet surtout l'utilisation des capteurs et outils qui sont disponibles sur la cible.

Dans la suite du TP nous allons utiliser un framework javascript qui permet de développer des applications à destination des smartphones et tablettes à partir des langages du web.

2 Présentation du framework ionic

Le framework ionic propose des objets graphiques adaptés aux cibles visées. Il utilise un autre framework javascript angular js.

Le framework ionic peut être récupéré à partir du site ici.

Plus simplement, pour créer une application utilisant le framework ionic, on utilise un interpréteur de commandes qui permet, entre autres possibilités, de créer un projet de base. Par exemple la commande suivante permet de créer un projet.

ionic start tpIonic blank --v2
  • start demande de créer un nouveau projer
  • tpIonic le nom du projet et le répertoire dans lequel sera stocké le projet
  • blank crée un projet avec une seule page
  • tabs crée un projet avec 3 classeurs (tabs)
  • sidemenu crée un projet avec un menu swipable
  • tutorial crée un projet pour suivre le tutoriel proposé ici.

La commande va créer un répertoire tpIonic et récupèrer les librairies nécessaires pour le développement.

Il est possible de tester l'application avec la commande :

cd tpIonic

puis

ionic serve

La commande compile le projet et le charge dans un serveur web de développement. Vous pouvez visualiser le résultat dans votre navigateur à l'adresse suivante : http://localhost:8100/

2.1 Structure d'un projet

Le point de départ se trouve dans le fichier src/index.html et plus particulièrement la balise

<ion-app> </ion-app>

Le style de l'application

<link href="build/main.css" rel="stylesheet">

est le résultat d'une compilation des différents fichiers de style déclarés dans le projet.

Le code javascript se trouve dans le fichier

<script src="build/main.js"></script>

résultat de la compilation du code javascript contenu dans le répertoire src et des librairies tiers utilisées.

La librairie cordova

<script src="cordova.js"></script>

permet d'exécuter l'application sur le smartphone cible.

Le point d'entrée du code javascript se trouve dans le fichier

src/app/app.module.ts

Il s'agit d'un code qui suit la syntaxe typescript (ES6/ES7) qui est transformé en javascript ES5 utilisé par les navigateurs actuels. L'application est composée de modules.

 @NgModule({
               declarations: [MyApp,HelloIonicPage, ItemDetailsPage, ListPage],
               imports: [IonicModule.forRoot(MyApp)],
               bootstrap: [IonicApp],
               entryComponents: [MyApp,HelloIonicPage,ItemDetailsPage,ListPage],
               providers: []
             })
             export class AppModule {}

Un module est une partie autonome dans l'application. Chaque application désigne un module racine. Un module déclare des composants (component), qui représentent l'interface utilisateur.

 @Component({
               templateUrl: 'app.html'
             })
             export class MyApp {
               rootPage = HomePage;
             
               constructor(platform: Platform) {
                 platform.ready().then(() => {
                   StatusBar.styleDefault();
                   Splashscreen.hide();
                 });
               }
             }

Un composant est une classe javascript (ES6) avec l'annotation @Component qui permet de préciser le fichier html (app.html) qui décrit l'interface.

<ion-nav [root]="rootPage"></ion-nav>

Dans la page app.html, on utilise la balise ionic <ion-nav> qui est un conteneur. L'instruction [root]="rootPage" est interprétée par le framework angular js, elle affecte à la directive root l'expression qui se trouve à l'intérieur des gullemets (ici la variable rootPage). Si on examine le code du composant app.component.ts, la variable rootPage vaut HomePage (rootPage = HomePage;). Le conteneur va afficher le composant HomePage (dans le fichier src/page/home.ts).

2.2 Ajout d'une nouvelle page

L'interpréteur de commandes ionic permet d'ajouter de nouvelles pages. Nous allons l'utiliser pour ajouter une page qui affiche une liste.

En tapant la commande

ionic g page Courses

dans le répertoire racine du projet, on ajoute le répertoire courses dans le répertoire pages. Le répertoire courses contient 3 fichiers :

  • courses.html l'interface utilisateur
  • courses.scss le style de la page
  • courses.ts le code javascript de la page

Modifier le fichier courses.ts avec le code suivant :

 import { Component } from '@angular/core';
             import { NavController} from 'ionic-angular';
             
             @Component({
               selector: 'page-courses',
               templateUrl: 'courses.html'
             })
             export class CoursesPage {
               courses: any;
             
               constructor(public navCtrl: NavController) {
             
                 this.courses = [
                   'Pain',
                   'lait',
                   'Fromage',
                   'Saucisse',
                   'Pommes',
                   'Bananes',
                   'Vin',
                   'Chocolat',
                   'Avocat',
                   'Moutarde',
                   'Gateaux au beurre',
                   'Mouchoirs'
                 ];
               }
             }

Modifier le fichier courses.html avec le code suivant:

 <ion-header>
               <ion-navbar>
                 <ion-title>Courses</ion-title>
               </ion-navbar>
             </ion-header>
             
             
             <ion-content>
               <ion-list>
                 <ion-item *ngFor="let aliment of courses">{{aliment}}</ion-item>
               </ion-list>
             </ion-content>

La navigation se fera à l'aide d'onglets. Modifier le fichier home.ts pour déclarer le premier onglet (courses) en utilisant le code suivant:

import { NavController } from 'ionic-angular';
            import {CoursesPage} from "../courses/courses";
            
            @Component({
              selector: 'page-home',
              templateUrl: 'home.html'
            })
            export class HomePage {
              tabCoursesRoot: any = CoursesPage;
            
              constructor(public navCtrl: NavController) {
               
              }
            }

Nous allons modifier le fichier home.html avec le code suivant:

<ion-tabs>
              <ion-tab [root]="tabCoursesRoot" tabTitle="Courses" tabIcon="basket"></ion-tab>
            </ion-tabs>

Il faut ensuite déclarer le nouveau composant dans le module (fichier app.module.ts), en utilisant le code suivant:

import {NgModule, ErrorHandler} from "@angular/core";
            import {IonicApp, IonicModule, IonicErrorHandler} from "ionic-angular";
            import {MyApp} from "./app.component";
            import {HomePage} from "../pages/home/home";
            import {CoursesPage} from "../pages/courses/courses";
            
            @NgModule({
                declarations: [
                    MyApp,
                    HomePage,
                    CoursesPage,
                ],
                imports: [
                    IonicModule.forRoot(MyApp)
                ],
                bootstrap: [IonicApp],
                entryComponents: [
                    MyApp,
                    HomePage,
                    CoursesPage
                ],
                providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
            })
            export class AppModule {
            }

La page http://localhost:8100/ dans le navigateur doit afficher la liste des courses.

2.3 Page avec une liste d'éléments modifiable

Nous allons refaire la même opération pour gérer une liste de notes que l'on pourra modifier.

  1. Taper la commande ionic g page Notes
  2. Modifier le fichier notes.ts avec le code suivant:

    import { Component } from '@angular/core';
                import { NavController, AlertController } from 'ionic-angular';
                
                @Component({
                selector: 'page-notes',
                templateUrl: 'notes.html'
                })
                export class NotesPage {
                
                  notes: any = [];
                
                  constructor(public navCtrl: NavController, public alertCtrl: AlertController) {
                
                  }
                
                  addNote(){
                
                      let prompt = this.alertCtrl.create({
                          title: 'Ajoute Note',
                          inputs: [{
                              name: 'title'
                          }],
                          buttons: [
                              {
                                  text: 'Annule'
                              },
                              {
                                  text: 'Ajoute',
                                  handler: data => {
                                      this.notes.push(data);
                                  }
                              }
                          ]
                      });
                
                      prompt.present();
                  }
                
                  editNote(note){
                
                      let prompt = this.alertCtrl.create({
                          title: 'Edite Note',
                          inputs: [{
                              name: 'title'
                          }],
                          buttons: [
                              {
                                  text: 'Annule'
                              },
                              {
                                  text: 'Sauve',
                                  handler: data => {
                                      let index = this.notes.indexOf(note);
                
                                      if(index > -1){
                                        this.notes[index] = data;
                                      }
                                  }
                              }
                          ]
                      });
                
                      prompt.present();       
                
                  }
                
                  deleteNote(note){
                
                      let index = this.notes.indexOf(note);
                
                      if(index > -1){
                          this.notes.splice(index, 1);
                      }
                  }
                }
  3. Modifier le fichier notes.html avec le code suivant:

    <ion-header>
                
                  <ion-navbar>
                    <ion-title>Notes</ion-title>
                    <ion-buttons end>
                        <button ion-button icon-only (click)="addNote()"><ion-icon name="add"></ion-icon></button>
                    </ion-buttons>
                  </ion-navbar>
                
                </ion-header>
                
                <ion-content>
                
                    <ion-list>
                
                        <ion-item-sliding *ngFor="let note of notes">
                
                            <ion-item>
                                {{note.title}}
                            </ion-item>
                
                            <ion-item-options>
                                <button ion-button icon-only (click)="editNote(note)" light>
                                    <ion-icon name="paper"></ion-icon>
                                </button>
                                <button ion-button icon-only (click)="deleteNote(note)" danger>
                                    <ion-icon name="trash"></ion-icon>
                                </button>
                            </ion-item-options>
                
                        </ion-item-sliding>
                
                    </ion-list>
                
                </ion-content>
  4. Modifier les fichiers home.ts, home.html (icon paper) et app.component.ts pour intégrer cette nouvelle page.

2.4 Tester votre application

Nous avons maintenant une application avec plusieurs pages. Il a été possible de tester son fonctionnement à partir d'un navigateur, nous allons maintenant la tester sur une cible.

Il faut que notre développement est accès à l'environnement de développement android (SDK). Pour cela il faut donner une valeur à la variable d'environnement ANDROID_HOME à l'aide de la commande suivante :

  export ANDROID_HOME=/usr/local/Android/Sdk
  1. Ajouter une nouvelle architecture cible, par exemple, android, taper la commande suivante:

    ionic platform add android

  2. Gestion du proxy et de l'API des machines de TP

    Dans l'étape qui suit, la commande gradle qui permet de construire l'application pour la cible android à besoin d'un accès sur le web. Vous devez ajouter le fichier gradle.properties dans le répertoire platforms/android

    
                  systemProp.http.proxyHost=cache-etu.univ-artois.fr
                  systemProp.https.proxyPort=3128
                  org.gradle.jvmargs=-Xmx1536m
                  systemProp.https.proxyHost=cache-etu.univ-artois.fr
                  systemProp.http.proxyPort=3128

    Vous devez modifier les fichiers platforms/android/AndroidManifest.xml, platforms/android/project.properties et platforms/android/CordovaLib/project.properties. Dans les trois fichiers indiqués, il faut remplacer la référence à l'API 25 par une référence à l'API 24 qui est actuellement installée sur les machines de TP.

    Pour platforms/android/project.properties et platforms/android/CordovaLib/project.properties :

        ...
                    target=android-24

    et pour platforms/android/AndroidManifest.xml

       <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="24" />
  3. Lancer l'émulateur avec la commande:

    ionic emulate android

Nous avons pu réaliser une application qui s'exécute sur un smartphone qui utilise le système android, on aurait pu faire la même chose sur un smartphone iOS , Windows Phone ou encore BlackBerry OS.

3 Persistance des données

Dans cette section, nous allons créer un service pour nous permettre de récupérer des données en local ou encore sur le réseau. Les données sont stockées dans le fichier src/assets/data/donnees.json, vous pouvez récupérer le contenu de ce fichier ici.

3.1 Création d'un provider

Nous allons créer un service (une classe qui n'a pas d'interface graphique) qui aura pour tâche d'accéder aux données stockées sur la cible (par exemple les préférences de l'utilisateur). L'interpréteur ionic permet la création d'un service

ionic g provider iBookData

  1. Stockage des données en local

    Nous allons utiliser un fichier de données que nous allons lire à la demande. Le fichier se trouve sur moodle donnees.json. Créez un répertoire data dans le répertoire assets et placez le fichier de données dans le répertoire data.

  2. Modification du fichier i-book-data

    Pour récupérer les données dynamiquement, nous allons créer une méthode dans le fichier providers/i-book-data.ts. Voici le code à ajouter pour la méthode getLocalData() :

      getLocalData():Observable<any> {
                    return this.http.get("assets/data/donnees.json").map(res => res.json().Books);
                  }
  3. Modification du fichier app-module.ts

    il faut ajouter IBookData dans la liste des providers

       // ...
                   providers: [{provide: ErrorHandler, useClass: IonicErrorHandler},
                       IBookData]
                   // ...

    3.1 Ajouter la page livres.

La commande suivante (déjà utilisée) permet d'ajouter une nouvelle page

ionic g page livres

modifier le fichier les fichiers home.ts home.html et app.component.ts pour pouvoir accéder à la page livres.

  export class HomePage {
                tabCoursesRoot: any = CoursesPage;
                tabNotesRoot: any = NotesPage;
                tabLivresRoot: any = LivresPage;
              }
  <ion-tabs>
                <ion-tab [root]="tabCoursesRoot" tabTitle="Courses" tabIcon="basket"></ion-tab>
                <ion-tab [root]="tabNotesRoot" tabTitle="Notes" tabIcon="paper"></ion-tab>
                <ion-tab [root]="tabLivresRoot" tabTitle="Livres" tabIcon="book"></ion-tab>
              </ion-tabs>

puis modifier la page livres.ts pour pouvoir récupérer les données

  @Component({
                selector: 'page-livres',
                templateUrl: 'livres.html'
              })
              export class LivresPage {
                livres: any;
              
                constructor(public navCtrl: NavController, public navParams: NavParams, private iBookData: IBookData) {
                  iBookData.getLocalData().subscribe(data => {
                    this.livres = data;
                  });
                }
              
                ionViewDidLoad() {
                  console.log('ionViewDidLoad LivresPage');
                }
              
              }

et le fichier livres.html

   <ion-header>
               
                 <ion-navbar>
                   <ion-title>livres</ion-title>
                 </ion-navbar>
               
               </ion-header>
               
               
               <ion-content padding>
                 <ion-list no-lines>
                   <button detail-none ion-item *ngFor="let livre of livres; let i = index;">
                     <ion-avatar item-left>
                       <img [src]="livre.Image">
                     </ion-avatar>
                     <h2>{{livre.Title}}</h2>
                     <p>{{livre.SubTitle}}</p>
                   </button>
                 </ion-list>
               </ion-content>

3.2 Utilisation du système de base de données SQLite disponible sur les smartphones

Nous allons reprendre la page notes qui permettait de gérer une liste de notes sans pouvoir la conserver d'une exécution à l'autre. Pour cela il faut importer un nouveau module Storage proposé par le framework ionic. Ce module choisit une solution de stockage local en fonction de la cible sur laquelle l'application s'exécute. Si l'application est exécutée dans un navigateur, les données seront stockées par lui en local. Si l'application est exécutée sur un smartphone, c'est le SGBD SQLite qui sera utilisé. Le choix se fait sans que le programmeur est quoi que ce soit à prévoir.

3.2.1 Ajouter un nouveau service storageData.

ionic g provider storage-data

  1. Création d'un nouveau type de données Note

    Nous allons définir la structure des données qui va permettre de stocker les notes. Dans un répertoire entities nous allons créer un fichier Note.js qui va définir la structure. Ici la structure de données se résume à une seule propriété.

      export interface Note {
                    description: string;
                }
  2. Modification du fichier storage-data.js en utilisant le code suivant :

    
                  import {Injectable} from "@angular/core";
                  import {Storage} from "@ionic/storage";
                  import {Observable} from "rxjs";
                  import {Note} from "../entities/Note";
                
                  @Injectable()
                  export class StorageData {
                
                      constructor(public storage: Storage) {
                          console.log('Hello Storage Provider');
                      }
                      getNotes(): Observable<any[]> {
                          return Observable.fromPromise(this.storage.get('notes'))
                              .map(data => {
                                  console.log(data);
                                  if (data !== null)
                                      return this.mapNotes(data);
                                  else {
                                      let notes: Note[] = [];
                                      return notes;
                                  }
                              });
                      }
                
                      mapNotes = (r: string): Note[] => {
                          return JSON.parse(r).map(this.toNote);
                      }
                
                      toNote = (r: any): Note => {
                          let note = <Note>({
                              description: r.description,
                          });
                          return note;
                      }
                
                      save(note): Observable<Note[]> {
                          let newNote = JSON.stringify(note);
                          return Observable.fromPromise(this.storage.set('notes', newNote))
                              .map(this.mapNotes);
                      }
                  }

3.2.2 Ajouter une nouvelle page notesPlus.

Pour créer la nouvelle page, taper la commande suivante :

ionic g page notesPlus

Après avoir modifier les fichiers home.ts et home.html :

  1. Modifier le code de la classe notes-plus.ts.

      import {Component, OnInit} from "@angular/core";
                  import {NavController, AlertController} from "ionic-angular";
                  import {StorageData} from "../../providers/storageData";
                  import {Note} from "../../entities/Note";
                
                  @Component({
                      selector: 'page-notes-plus',
                      templateUrl: 'notes-plus.html'
                  })
                  export class NotesPlusPage implements OnInit {
                
                      notes: Note[] = [];
                
                      constructor(public navCtrl: NavController, public alertCtrl: AlertController, private storageData: StorageData) {
                      }
                
                      addNote() {
                          let prompt = this.alertCtrl.create({
                              title: 'Ajoute Note',
                              inputs: [{
                                  name: 'description',
                                  placeholder: 'Description'
                              }],
                              buttons: [
                                  {
                                      text: 'Annule'
                                  },
                                  {
                                      text: 'Ajoute',
                                      handler: data => {
                                          console.log(data);
                                          this.notes.push(data);
                                          this.storageData.save(this.notes);
                                      }
                                  }
                              ]
                          });
                
                          prompt.present();
                      }
                
                      editNote(note) {
                          let prompt = this.alertCtrl.create({
                              title: 'Edite Note',
                              inputs: [{
                                  name: 'description',
                                  placeholder: 'Description'
                              }],
                              buttons: [
                                  {
                                      text: 'Annule'
                                  },
                                  {
                                      text: 'Sauve',
                                      handler: data => {
                                          let index = this.notes.indexOf(note);
                
                                          if (index > -1) {
                                              this.notes[index] = data;
                                              this.storageData.save(this.notes);
                                          }
                                      }
                                  }
                              ]
                          });
                
                          prompt.present();
                
                      }
                
                      deleteNote(note) {
                          let index = this.notes.indexOf(note);
                
                          if (index > -1) {
                              this.notes.splice(index, 1);
                              this.storageData.save(this.notes);
                          }
                      }
                
                
                      ngOnInit(): void {
                          this.storageData.getNotes().subscribe((data) => {
                              this.notes = data;
                              if (this.notes == null) {
                                  this.notes = [];
                              }
                          });
                      }
                
                      ionViewDidLoad() {
                          console.log('ionViewDidLoad NotesPlusPage');
                      }
                
                  }
  2. Modifier le fichier notes-plus.html.

    
                  <ion-header>
                
                      <ion-navbar>
                          <ion-title>NotesPlus</ion-title>
                          <ion-buttons end>
                              <button ion-button icon-only (click)="addNote()">
                                  <ion-icon name="add"></ion-icon>
                              </button>
                          </ion-buttons>
                      </ion-navbar>
                
                  </ion-header>
                
                
                  <ion-content padding>
                      <ion-list>
                
                          <ion-item-sliding *ngFor="let note of notes">
                
                              <ion-item>
                                  {{note.description}}
                              </ion-item>
                
                              <ion-item-options>
                                  <button ion-button icon-only (click)="editNote(note)" light>
                                      <ion-icon name="paper"></ion-icon>
                                  </button>
                                  <button ion-button icon-only (click)="deleteNote(note)" danger>
                                      <ion-icon name="trash"></ion-icon>
                                  </button>
                              </ion-item-options>
                          </ion-item-sliding>
                      </ion-list>
                  </ion-content>

3.2.3 Le fichier app/app.module.ts

Modifier le fichier app/app.module.ts avec le code suivant :

  import {NgModule, ErrorHandler} from "@angular/core";
              import {IonicApp, IonicModule, IonicErrorHandler} from "ionic-angular";
              import {IonicStorageModule} from "@ionic/storage";
              import {MyApp} from "./app.component";
              import {HomePage} from "../pages/home/home";
              import {CoursesPage} from "../pages/courses/courses";
              import {NotesPage} from "../pages/notes/notes";
              import {LivresPage} from "../pages/livres/livres";
              import {IBookData} from "../providers/i-book-data";
              import {NotesPlusPage} from "../pages/notes-plus/notes-plus";
              import {StorageData} from "../providers/storageData";
              
              @NgModule({
                  declarations: [
                      MyApp,
                      HomePage,
                      CoursesPage,
                      NotesPage,
                      NotesPlusPage,
                      LivresPage,
                  ],
                  imports: [
                      IonicModule.forRoot(MyApp),
                      IonicStorageModule.forRoot()
                  ],
                  bootstrap: [IonicApp],
                  entryComponents: [
                      MyApp,
                      HomePage,
                      CoursesPage,
                      NotesPage,
                      NotesPlusPage,
                      LivresPage,
                  ],
                  providers: [{provide: ErrorHandler, useClass: IonicErrorHandler},
                      Storage,
                      StorageData,
                      IBookData]
              })
              export class AppModule {
              }

3.3 Connexion sur le web

Il est parfois nécessaire de récupérer des données sur le web, pour cela l'application va lancer une requête vers un service qui est à l'écoute. Dans notre exemple nous allons utiliser le site it-book qui met à la disposition de ses utilisateurs une api REST permettant d'intérroger sa base de données.

3.3.1 Modification du fichier i-book-data.ts avec le code suivant :

  import {Injectable} from "@angular/core";
              import {Http, Response} from "@angular/http";
              import "rxjs/add/operator/map";
              import {Observable} from "rxjs";
            
              @Injectable()
              export class IBookData {
                  _page: number;
                  _requete: string;
              
                  constructor(public http: Http) {
                      console.log('Hello IBookData Provider');
                      this._requete = encodeURI("javascript json");
                      this._page = 1;
                  }
              
                  getLocalData(): Observable<any> {
                      let url = "assets/data/donnees.json";
                      console.log("URL = " +url);
                      return this.http.get("assets/data/donnees.json").map(res => res.json().Books);
                  }
              
                  getRemoteData(): Observable<any> {
                      let url = "http://it-ebooks-api.info/v1/search/"+this._requete+"/page/" + this._page;
                      console.log("URL = "+url);
                      return this.http.get(url).map(res => {
                          // console.log(res);
              
                          let data = [];
                          try {
                              data = res.json().Books;
                              if (data === undefined)
                                  data = [];
                          } catch (e) {
                              console.log("Erreur connexion : " + e.toString());
                          }
                          return data;
                      }).catch(this.handleError);
                  }
              
                  private handleError (error: Response | any) {
                      let errMsg: string;
                      if (error instanceof Response) {
                          const body = error.json() || '';
                          const err = body.error || JSON.stringify(body);
                          errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
                      } else {
                          errMsg = error.message ? error.message : error.toString();
                      }
                      console.error("Message d'erreur: " + errMsg);
                      return Observable.throw(errMsg);
                  }
              
                  incPage() {
                      this._page++;
                  }
              
              
                  decPage() {
                      if (this._page > 1)
                          this._page--;
                  }
              
                  setRequete(r: string) {
                      this._requete = encodeURI(r);
                      this._page = 1;
                  }
              
              }

3.3.2 Ajouter une nouvelle page livresPlus.

Pour créer la nouvelle page, taper la commande suivante :

ionic g page livresPlus

Après avoir modifier les fichiers home.ts et home.html :

  1. Modifier le code de la classe livres-plus.ts.

      import {Component, OnInit} from "@angular/core";
                  import {NavController, NavParams, AlertController} from "ionic-angular";
                  import {IBookData} from "../../providers/i-book-data";
                
                  @Component({
                      selector: 'page-livres-plus',
                      templateUrl: 'livres-plus.html'
                  })
                  export class LivresPlusPage implements OnInit{
                      livres: any;
                
                      constructor(public navCtrl: NavController, public navParams: NavParams, public alertCtrl: AlertController, private iBookData: IBookData) {
                      }
                
                      doInfinite(infiniteScroll) {
                          this.iBookData.incPage();
                          this.iBookData.getRemoteData().subscribe(data => {
                              console.log("livres : ", data);
                              if (data.length > 0)
                                  for (let livre of data)
                                      this.livres.push(livre);
                              infiniteScroll.complete();
                          });
                      }
                
                
                      ngOnInit(): void {
                          this.iBookData.getRemoteData().subscribe(data => {
                              console.log(data);
                              this.livres = data;
                          });
                      }
                
                      ionViewDidLoad() {
                          console.log('ionViewDidLoad LivresPlusPage');
                      }
                
                      changeRequest() {
                          let prompt = this.alertCtrl.create({
                              title: 'Requête',
                              inputs: [{
                                  name: 'requete'
                              }],
                              buttons: [
                                  {
                                      text: 'Annule'
                                  },
                                  {
                                      text: 'Recherche',
                                      handler: data => {
                                          console.log(data);
                                          this.iBookData.setRequete(data.requete);
                                          this.ngOnInit();
                                      }
                                  }
                              ]
                          });
                          prompt.present();
                      }
                
                  }
  2. Modifier le code de la classe livres-plus.html.

    
                  <ion-header>
                
                    <ion-navbar>
                      <ion-title>Livres Plus</ion-title>
                      <ion-buttons end>
                        <button ion-button icon-only (click)="changeRequest()"><ion-icon name="search"></ion-icon></button>
                      </ion-buttons>
                
                    </ion-navbar>
                
                  </ion-header>
                
                
                  <ion-content padding>
                    <ion-list no-lines>
                      <button detail-none ion-item *ngFor="let livre of livres; let i = index;">
                        <ion-avatar item-left>
                          <img [src]="livre.Image">
                        </ion-avatar>
                        <h2>{{livre.Title}}</h2>
                        <p>{{livre.SubTitle}}</p>
                      </button>
                    </ion-list>
                    <ion-infinite-scroll (ionInfinite)="doInfinite($event)">
                      <ion-infinite-scroll-content></ion-infinite-scroll-content>
                    </ion-infinite-scroll>
                  </ion-content>