• 20 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 28/11/2019

Intégrez un backend - base de données

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Base de données

Vous allez maintenant utiliser la base de données NoSQL proposée par Firebase pour enregistrer les données de l'application afin qu'elles perdurent après la fermeture de l'application.  Vous allez également modifier la structure de  AppareilsService  pour ajouter un niveau d'abstraction : au lieu de modifier les données directement, vous allez utiliser la programmation réactive avec RxJS pour modifier et observer les données de l'application.

Avant tout, installez le package rxjs-compat à votre projet pour vous assurer de la compatibilité du code ci-dessous (depuis Angular 6) :

npm install rxjs-compat --save

Pour intégrer tout cela, il va falloir apporter quelques modifications à  AppareilsService .  Commencez par créer un Subject qui émettra la liste des appareils :

export class AppareilsService {
  
  appareils$ = new Subject<Appareil[]>();

  appareilsList: Appareil[] = [
    {
      name: 'Machine à laver', ...

Ensuite, créez une méthode qui fera émettre ce Subject :

  emitAppareils() {
    this.appareils$.next(this.appareilsList.slice());
  }

Vous pouvez dès maintenant modifier  AppareilsPage  pour prendre en compte ce changement.  Ajoutez une Subscription pour souscrire au Subject, et modifiez le lifecycle du component (utilisez  OnInit  et  OnDestroy  plutôt que  ionViewWillEnter ) :

import { Component, OnDestroy, OnInit } from '@angular/core';
import { MenuController, ModalController, NavController } from 'ionic-angular';
import { SingleAppareilPage } from './single-appareil/single-appareil';
import { Appareil } from '../../models/Appareil';
import { AppareilsService } from '../../services/appareils.service';
import { AppareilFormPage } from './appareil-form/appareil-form';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'page-appareils',
  templateUrl: 'appareils.html'
})
export class AppareilsPage implements OnInit, OnDestroy {

  appareilsList: Appareil[];
  appaeilsSubscription: Subscription;

  constructor(private modalCtrl: ModalController,
              private appareilsService: AppareilsService,
              private menuCtrl: MenuController,
              private navCtrl: NavController) {}

  ngOnInit() {
    this.appaeilsSubscription = this.appareilsService.appareils$.subscribe(
      (appareils: Appareil[]) => {
        this.appareilsList = appareils.slice();
      }
    );
    this.appareilsService.emitAppareils();
  }

  onLoadAppareil(index: number) {
    let modal = this.modalCtrl.create(SingleAppareilPage, {index: index});
    modal.present();
  }

  onToggleMenu() {
    this.menuCtrl.open();
  }

  onNewAppareil() {
    this.navCtrl.push(AppareilFormPage);
  }

  ngOnDestroy() {
    this.appaeilsSubscription.unsubscribe();
  }
}

L'application continue de fonctionner, intégrant la nouvelle abstraction.

Vous allez maintenant créer des méthodes pour l'enregistrement et la récupération des données dans  AppareilsService  (ces méthodes retourneront des Promise, car les méthodes Firebase qu'elles encapsulent sont asynchrones) :

  saveData() {
    return new Promise((resolve, reject) => {
      firebase.database().ref('appareils').set(this.appareilsList).then(
        (data: DataSnapshot) => {
          resolve(data);
        },
        (error) => {
          reject(error);
        }
      );
    });
  }

  retrieveData() {
    return new Promise((resolve, reject) => {
      firebase.database().ref('appareils').once('value').then(
        (data: DataSnapshot) => {
          this.appareilsList = data.val();
          this.emitAppareils();
          resolve('Données récupérées avec succès !');
        }, (error) => {
          reject(error);
        }
      );
    });
  }

La méthode  database().ref('appareils')  crée une référence au endpoint  appareils  de votre base de données.  Ensuite, pour l'enregistrement des données, la méthode  set()  permet d'écrire les données passées en argument au endpoint (et de créer cet endpoint s'il n'existe pas encore) et retourne une Promise, permettant de confirmer l'enregistrement ou d'en voir l'erreur survenue.  Pour la récupération, vous utilisez ici la méthode  once('value')  qui retourne une Promise qui se résout avec un objet de type  DataSnapshot  (type mis à disposition par Firebase).  Ensuite, pour en sortir les données, il faut exécuter la méthode  val()  sur ce  DataSnapshot .  Vous exécutez ensuite  emitAppareils()  pour faire émettre le Subject et mettre à jour l'application.

Vous allez maintenant implémenter ces deux méthodes dans  AppareilsPage .  Je vais en profiter pour vous montrer deux éléments Ionic très utiles :  LoadingController  et  ToastController .  Commencez par les injecter dans  AppareilsPage  en les important depuis  ionic-angular :

  constructor(private modalCtrl: ModalController,
              private appareilsService: AppareilsService,
              private menuCtrl: MenuController,
              private navCtrl: NavController,
              private toastCtrl: ToastController,
              private loadingCtrl: LoadingController) {}

LoadingController  permet d'afficher un spinner qui empêche l'utilisateur d'interagir avec l'application.  Cet élément est extrêmement utile pour faire patienter l'utilisateur pendant, par exemple, une interaction avec un serveur qui prend du temps.

ToastController  permet d'afficher des messages à l'utilisateur pendant une durée et à un endroit déterminés.  Vous vous en servirez pour afficher des messages de confirmation ou d'erreur pour l'utilisateur lors des interactions avec le serveur.

Commencez par créer  onSaveList()  qui sera exécutée quand l'utilisateur cliquera sur le bouton Enregistrer (que vous créerez par la suite) :

  onSaveList() {
    let loader = this.loadingCtrl.create({
      content: 'Sauvegarde en cours…'
    });
    loader.present();
    this.appareilsService.saveData().then(
      () => {
        loader.dismiss();
        this.toastCtrl.create({
          message: 'Données sauvegardées !',
          duration: 3000,
          position: 'bottom'
        }).present();
      },
      (error) => {
        loader.dismiss();
        this.toastCtrl.create({
          message: error,
          duration: 3000,
          position: 'bottom'
        }).present();
      }
    );
  }

Cette méthode commence par créer le spinner à l'aide de la méthode  create()  , accompagné du message "Sauvegarde en cours…", et par l'afficher avec  present()  (vous le stockez dans une variable afin de pouvoir la détruire ensuite).  Ensuite, elle appelle la méthode  saveData()  de  AppareilsService  et profite de sa nature asynchrone.  Si  saveData()  réussit, cette méthode détruit le spinner avec  dismiss() , crée un message de confirmation qui s'affiche pendant trois secondes en bas de l'écran et l'affiche.  Si  saveData()  échoue, c'est un message d'erreur qui s'affiche.

Vous pouvez maintenant créer une deuxième méthode  onFetchList()  pour la récupération des données, qui suivra le même schéma :

  onFetchList() {
    let loader = this.loadingCtrl.create({
      content: 'Récuperation en cours…'
    });
    loader.present();
    this.appareilsService.retrieveData().then(
      () => {
        loader.dismiss();
        this.toastCtrl.create({
          message: 'Données récupérées !',
          duration: 3000,
          position: 'bottom'
        }).present();
      },
      (error) => {
        loader.dismiss();
        this.toastCtrl.create({
          message: error,
          duration: 3000,
          position: 'bottom'
        }).present();
      }
    );
  }

Vous pouvez maintenant créer des boutons dans le template pour exécuter ces méthodes :

    <ion-card>
        <ion-card-header>Données</ion-card-header>
        <ion-card-content>
            <button ion-button block outline (click)="onSaveList()">Enregistrer</button>
            <button ion-button block outline (click)="onFetchList()">Récupérer</button>
        </ion-card-content>
    </ion-card>
</ion-content>

Il reste une dernière étape pour que l'application soit totalement fonctionnelle.  La méthode  addAppareil()  de  AppareilsService  ne met pas à jour le Subject, donc il suffit d'y ajouter une ligne :

  addAppareil(appareil: Appareil) {
    this.appareilsList.push(appareil);
    this.emitAppareils();
  }

Vous pouvez maintenant tester votre application en sauvegardant les données, en les modifiant, en les récupérant, etc. Votre application communique correctement avec votre base de données Firebase !

Exemple de certificat de réussite
Exemple de certificat de réussite