Bonjour à tous! Dans cet tutoriel nous allons recréer une application Ionic Todolist en partant de zéro.

Je vous montrerais toutes les étapes, du design aux bases de données, ainsi qu’aux fonctionnalités de notre Todolist Ionic.

C’est un exercice très utile is vous commencez dans le développement mobile avec Ionic et Firebase. Vous allez apprendre énormément de chose dans ce tutoriel Ionic 4.

IONIC TODOLIST: Créer une application To Do List avec Ionic en partant de zéro

Pour créer cette application Todolist avec Ionic, nous allons suivre les étapes suivantes:

  1. Créer le thème de l’application Ionic Todolist
  2. Connecter son application Ionic à Firebase avec AngularFire
  3. Ajouter une tâche à notre Todolist depuis Ionic
  4. Afficher les éléments de la Todolist dans Ionic
  5. Cocher les cases et les synchroniser avec Firebase

Comment créer le thème de l’application Ionic Todolist ?

Pour commencer ce tutoriel Ionic 4, nous allons créer une application de type Blank, vierge en français, avec une seule page Home.

Pour créer cette application Todolist, entrez la commande Ionic suivante dans votre terminal:

ionic start Todolist blank

Si votre terminal vous demande de choisir le framework de développement, choisissez Angular.

Nous allons directement attaquer le thème de l’application, pour cela rendez-vous dans le fichier HTML de votre page d’accueil Home:

src/app/home/home.page.html

Vous pouvez commencer par changer le titre de votre application, par exemple en mettant Ionic Todolist:

<ion-title>
  Ionic Todolist
</ion-title>

Ensuite nous allons modifier la couleur de notre header, en lui donnant une nouvelle couleur.

Pour en ajouter une ou en modifier une existante, rendez-vous dans le fichier SCSS suivant:

src/theme/variables.scss

Pour obtenir un thème cohérent pour notre application, je vous propose d’ajouter la couleur #5a8ca4 à votre menu, pour se fondre avec le fond de notre page.

Pour aller plus vite, vous pouvez directement les valeur hexadécimales de la couleur primary:

/** primary **/
--ion-color-primary: #5a8ca4;
--ion-color-primary-rgb: 56, 128, 255;
--ion-color-primary-contrast: #ffffff;
--ion-color-primary-contrast-rgb: 255, 255, 255;
--ion-color-primary-shade: #4f7c90;
--ion-color-primary-tint: #6ba5c0;

De cette manière vous pouvez donner à votre toolbar l’attribut color=”primary” pour la colorer en bleu-gris:

<ion-toolbar color="primary">
  <ion-title>
    Todolist
  </ion-title>
</ion-toolbar>

Passons maintenant au fond de notre page Home, auquel nous souhaitons ajouter une image.

Pour commencer je vous invite à télécharger l’image que j’utilise dans le tutoriel, en cliquant sur l’image ci-dessous:

Placez ensuite cette image dans le dossier assets/ de votre application Ionic, de cette manière nous pourrons l’afficher dans notre page Home.

Reprenons donc le fichier HTML de notre page d’accueil, et ajoutons une boîte div à notre ion-content, pour afficher notre image en fond:

<ion-content>
  <div class="bg-img">
  
  </div>
</ion-content>

Nous donnons à cette boîte div la classe bg-img que nous allons déclarer dans le fichier CSS suivant:

src/app/home/home.page.scss

La déclaration de cette classe et assez simple, elle reprend certaines propriétés CSS que nous avons vu dans le tuto Ionic Netflix:

.bg-img {
    padding: 1px;
    height: 100%;
    width: 100%;
    background-image: url('../../assets/bg.jpg');
    background-repeat: no-repeat;
    background-size: cover;
}

De cette manière, notre image s’affichera au fond de notre page Home, prendra toute la place disponible et se centrera automatiquement.

Passons maintenant au contenu de notre page d’accueil, à commencer par la date du jour.

Pour cela nous allons afficher un titre h1 avec comme texte Aujourd’hui, tout simple et ensuite la date exacte du jour en français:

<ion-content>
  <div class="bg-img">

    <h1><b>Aujourd'hui</b></h1>
    <h5>{{ currentDate }}</h5>
    
  </div>
</ion-content>

La date du jour est stockée dans la variable currentDate que nous allons déclarer juste après.

Avant cela nous allons juste ajouter quelques propriétés CSS à nos titre, pour les colorer en blanc ou gris clair, et les espacer convenablement:

h1 {
    color: white;
    margin-left: 20px;
    font-size: 30px;
}
h5 {
    color: #e8e8e8;
    margin-left: 20px;
    margin-top: -7px;
    font-size: medium;
    margin-bottom: 15px;
    text-transform: capitalize;
}

Pour finir sur cette partie, nous pouvons passer au fichier TypeScript, dans lequel nous allons déclarer notre variable:

src/app/home/home.page.ts

À la suite de votre classe HomePage, vous pouvez déclarer la variable currentDate en tant que chaîne de caractère:

export class HomePage {
	currentDate: string;

Nous allons ensuite faire appel à la fonction JavaScript Date() pour accéder à la date du jour, que nous stockons dans une constante date:

const date = new Date();

Ensuite, et nous exécutons tout ce code dans le constructor() pour le lancer au chargement de notre page, nous convertissons cette date en chaîne de caractère au format Français:

constructor() {
  const date = new Date();
  const options = { weekday: 'long', month: 'long', day: 'numeric' };
  this.currentDate = date.toLocaleDateString('fr-FR', options);
}

Nous stockons bien la date actuelle dans notre variable currentDate, que nous affichons dans le header de notre page Home.

Comment connecter son application Ionic à Firebase avec AngularFire ?

Comme promis, c’est un tutoriel Ionic complet, dans lequel je réalise l’application de A à Z. Donc dans cette partie nous allons voir comment connecter un projet Firebase à notre application Ionic.

Bien évidemment si c’est la première que vous utilisez Firebase, je vous conseille de consulter ce tutoriel sur Ionic & Firebase: https://drissas.com/ionic-4-firebase/

Pour commencer, vous pouvez vous connecter à Firebase et créer un nouveau projet à l’adresse suivante: https://firebase.google.com/

Une fois que votre projet Firebase est créé, nous allons installer le plugin AngularFire: https://github.com/angular/angularfire

Je vous invite toujours à regarder la documentation officielle des plugins, qui proposent de nombreuses informations la plupart du temps.

Pour installer le plugin dans votre application Ionic, entrez la commande suivante:

npm install firebase @angular/fire --save

Une fois le plugin installé, nous allons le configurer dans le fichier suivant:

src/app/app.module.ts

Commencez par importer le module de configuration AngularFireModule pour associer notre application Ionic à notre projet Firebase.

Puis importer le module AngularFireDatabaseModule pour utiliser par la suite les fonctions associées aux bases de données:

import { AngularFireModule } from '@angular/fire';
import { AngularFireDatabaseModule } from '@angular/fire/database';

Une fois nos deux modules importés, nous déclarons une constante firebaseConfig pour stocker tous les codes de configuration de notre projet Firebase.

export const firebaseConfig = {
  apiKey: '****************************************',
  authDomain: 'todolist-*******.firebaseapp.com',
  databaseURL: 'https://todolist-*******.firebaseio.com',
  projectId: 'todolist-*******',
  storageBucket: 'todolist-*******.appspot.com',
  messagingSenderId: '**************',
  appId: '1:**************:web:**************'
};

Vous trouverez ces codes dans le menu Project Overview de Firebase, dans la rubrique application Web. Si vous ne les trouvez consultez le tuto sur Ionic & Firebase: https://drissas.com/ionic-4-firebase/

Une fois que nos plugins sont importés et nos codes de configuration déclarés, nous pouvons finalement déclarer nos modules dans le tableau imports et initialiser le module AngularFire:

imports: [
  BrowserModule,
  IonicModule.forRoot(),
  AppRoutingModule,
  AngularFireModule.initializeApp(firebaseConfig),
  AngularFireDatabaseModule,
],

Grâce à la fonction initializeApp() du module AngularFire, notre projet Firebase va être associé à notre application Ionic.

Pour pouvoir utiliser AngularFire dans notre page d’accueil, et gérer nos bases de données, rendez-vous dans le fichier TypeScript:

src/app/home/home.page.ts

Et importez le module AngularFireDatabase pour pouvoir utiliser les fonctions de gestion des bases de données:

import { AngularFireDatabase } from '@angular/fire/database';

Déclarez ensuite ce module dans le constructor() pour pouvoir l’utiliser dans le reste de votre page:

constructor(
	public afDB: AngularFireDatabase,
) {}

Voilà cette partie est terminée, notre application Ionic est bien associée à notre projet Firebase grâce au plugin AngularFire!

Comment ajouter une tâche à notre Todolist depuis Ionic ?

Passons maintenant à la partie la plus intéressante de notre tutoriel Ionic 4, l’ajout de tâche à notre todolist depuis Ionic.

Pour commencer nous allons créer le formulaire d’envoi de notre tâche, qui contiendra un champ texte tout simplement.

Nous allons contenir notre champ texte ainsi que le bouton d’envoi dans un ion-card comme ceci:

<ion-card>
 
</ion-card>

Puis, nous ajoutons à notre ion-card un ion-item qui contient pour le moment uniquement notre champ texte ion-input:

<ion-card>
  <ion-item lines="none">
    <ion-input [(ngModel)]="myTask" placeholder="Entrer une tâche"></ion-input>
  </ion-item>
</ion-card>

Ce champ texte est associé à la variable myTask que vous pouvez déclarer dans votre fichier home.page.ts:

myTask = '';

Enfin, nous allons créer un bouton pour ajouter notre tâche à notre base de données Firebase, que nous associons à la fonction addTaskToFirebase():

<ion-button (click)="addTaskToFirebase()" shape="round" slot="end">
  <ion-icon slot="icon-only" name="add"></ion-icon>
</ion-button>

Cette fonction est très simple, elle ajoute un nouvel item à notre table Tasks, en lui donnant les informations suivantes: le texte, la date, et l’état de la tâche:

addTaskToFirebase() {
  this.afDB.list('Tasks/').push({
    text: this.myTask,
    date: new Date().toISOString(),
    checked: false
  });
  this.showForm();
}

Une fois que la tâche est ajoutée à la base de données, nous exécutons la fonction showForm() que nous allons déclarer pour afficher ou cacher le formulaire d’envoi.

Pour commencer nous devons déclarer la variable booléenne addTask qui servira de condition d’affichage dans le HTML:

addTask: boolean;

Une fois cette variable déclarée, nous pouvons créer la fonction showForm() dont le but sera de changer la valeur de cette variable booléenne.

showForm() {
  this.addTask = !this.addTask;
  this.myTask = '';
}

Nous lui donnons à chaque fois sa valeur contraire pour passer de false à true et inversement. Nous réinitialisons à chaque fois le champ texte de notre formulaire, pour le vider à chaque envoi dans la base de données.

Maintenant que la fonction d’affichage ou de masquage de notre formulaire est crée, il nous faut créer un autre bouton pour l’exécuter.

Nous créons plus précisément deux boutons, associés à la même fonction mais dont le texte et l’icône sont différents selon le cas:

<ion-button *ngIf="!addTask" (click)="showForm()" expand="block" class="add-button">
  <ion-icon name="add" slot="start"></ion-icon>
  Ajouter une tâche
</ion-button>

<ion-button *ngIf="addTask" (click)="showForm()" expand="block" class="add-button">
  <ion-icon name="close" slot="start"></ion-icon>
  Annuler
</ion-button>

Vous pouvez également ajouter les propriétés CSS suivantes à vos boutons pour les colorer et les positionner en bas de votre écran:

.add-button {
    --background: #383a3e;
    position: absolute;
    bottom: 5px;
    width: 96%;
    --color: #ffffff;
    margin-left: 2%;
}

Voilà donc le rendu final de votre formulaire d’envoi de vos tâche dans Firebase, qui ne s’affiche que si on clique sur le bouton en bas:

<ion-card *ngIf="addTask">
  <ion-item lines="none">
    <ion-input [(ngModel)]="myTask" placeholder="Entrer une tâche"></ion-input>
    <ion-button (click)="addTaskToFirebase()" shape="round" slot="end">
      <ion-icon slot="icon-only" name="add"></ion-icon>
    </ion-button>
  </ion-item>
</ion-card>

De cette manière, lorsqu’on envoie une nouvelle tâche dans Firebase, on réinitialise le champ et on le cache par la même occasion.

Comment afficher les éléments de la Todolist dans Ionic ?

Nos informations concernant nos tâches sont maintenant stockées dans notre bases de données Firebase.

Le prochain travail consiste à récupérer ces informations et à les afficher dans notre page d’accueil Home.

Pour commencer nous créons la variable tasks sous forme de tableau pour pouvoir stocker toutes les informations de nos tâches:

tasks = [];

Nous utilisons le format de table pour nous permettre de parcourir cet variable sous forme de boucle for dans notre HTML, et ainsi afficher la liste des tâches.

Ensuite nous pouvons créer la fonction getTask() pour parcourir notre base firebase Tasks/ et récupérer mes informations de nos tâches:

getTasks() {
  this.afDB.list('Tasks/').snapshotChanges(['child_added', 'child_removed']).subscribe(actions => {
    this.tasks = [];
    actions.forEach(action => {
      this.tasks.push({
        key: action.key,
        text: action.payload.exportVal().text,
        hour: action.payload.exportVal().date.substring(11, 16),
        checked: action.payload.exportVal().checked
      });
    });
  });
}

La fonction s’exécutera à chaque fois qu’un élément sera ajouté un supprimé de notre table Tasks/ et à chaque fois nous réinitialisons la variable tasks.

Pour que cette fonction s’exécute au lancement de notre page, vous devez l’exécuter dans votre constructor() comme ceci:

constructor(
  public afDB: AngularFireDatabase,
) {
  const date = new Date();
  const options = { weekday: 'long', month: 'long', day: 'numeric' };
  this.currentDate = date.toLocaleDateString('fr-FR', options);
  this.getTasks();
}

Nous allons maintenant passer à l’affichage de notre todolist dans la page d’accueil de notre application Ionic.

Pour cela nous allons utiliser à nouveau les ion-card dont vous pouvez consulter la documentation officielle: https://ionicframework.com/docs/api/card

On créé donc simplement une première ion-card pour tester l’affichage du contenu, avec à l’intérieur un ion-tem qui contient simplement une case à cocher ainsi que nos informations:

<ion-card >
  <ion-item lines="none">
    <ion-checkbox color="success" slot="start"></ion-checkbox>
    <ion-label>
      <h2>Tâche</h2>
      <p>Heure</p>
    </ion-label>
  </ion-item>
</ion-card>

Il nous faut maintenant dynamiser un peu cet affichage de nos tâches, et pour cela nous allons créer une boucle for.

On utilise donc la directive ngFor pour parcourir notre tableau tasks et afficher individuellement chaque tâche de notre todolist.

On remplace bien sûr la valeur de notre tâche par le champ text de la variable task, de même que pour l’affichage de l’heure:

<ion-card *ngFor="let task of tasks">
  <ion-item lines="none">
    <ion-checkbox color="success" slot="start"></ion-checkbox>
    <ion-label>
      <h2 >{{ task.text }}</h2>
      <p>{{ task.jour }}</p>
    </ion-label>
  </ion-item>
</ion-card>

Pour l’instant on veut simplement afficher les tâches de notre Todolist dans Ionic, on ne gère pas encore le fait que notre tâche est coché ou non.

Pour permettre d’actualiser votre page, et de tester le bon rafraîchissement de vos tâches depuis Firebase, vous pouvez créer un bouton associé à la fonction getTasks():

<ion-button (click)="getTasks()">
  <ion-icon name="refresh" slot="icon-only"></ion-icon>
</ion-button>

Et par exemple comme moi, l’ajouter dans votre ion-header pour faire des tests régulièrement:

<ion-header>
  <ion-toolbar color="primary">
    <ion-title>
      Ionic Todolist
    </ion-title>
    <ion-buttons slot="end">
      <ion-button (click)="getTasks()">
        <ion-icon name="refresh" slot="icon-only"></ion-icon>
      </ion-button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>

Voilà c’est la fin de cette partie dans laquelle nous avons récupéré les informations de notre base de données Firebase et que nous les avons affiché dans la page d’accueil.

Notre prochain travail consiste à permettre de cocher ou de décocher une case, et à synchroniser avec Firebase.

Comment cocher les cases et les synchroniser avec Firebase ?

Nous allons donc commencer par synchroniser la valeur de notre checkbox entre firebase et Ionic.

Pour cela nous allons utiliser l’élément Ion Checkbox dont je vous recommande la documentation: https://ionicframework.com/docs/api/checkbox

Jusqu’à présent nous avions simplement créé cette checkbox, mais elle n’était lié à aucune variable.

Pour la rendre dynamique nous utilisons la syntaxe suivante pour notre ion-checkbox:

<ion-checkbox (ionChange)="changeCheckState(task)" color="success" [(ngModel)]="task.checked" slot="start"></ion-checkbox>

Le plus important étant la directive ngModel qui nous permet d’associer notre checkbox à notre variable task et à son champ checked:

[(ngModel)]="task.checked"

De cette manière, si la valeur de notre champ checked est à true dans Firebase, alors lors du chargement la checkbox sera coché.

Par contre pour changer sa valeur depuis Ionic, et lui affecter ce changement dans Firebase il faut rajouter l’évènement suivant:

(ionChange)="changeCheckState(task)"

Cela permet d’exécuter une fonction à chaque fois que nous cochons ou décochons notre ion-chebox.

Par exemple pour commencer nous pouvons simplement lui demander d’afficher dans la console la valeur de checkbox (true ou false):

changeCheckState(ev: any) {
  console.log('checked: ' + ev.checked);
}

Bien sûr plutôt que de simplement l’afficher, il nous faut aussi modifier la valeur correspondante dans Firebase, en mettant à jour la valeur du champ checked de notre tâche Firebase.

changeCheckState(ev: any) {
  console.log('checked: ' + ev.checked);
  this.afDB.object('Tasks/' + ev.key + '/checked/').set(ev.checked);
}

Puisque à chaque modification de nos tables, la fonction getTasks() va exécuter son code, nous allons mettre à jour en direct les informations de nos tâches dans Ionic.

Pour finir cette application Ionic Todolist, vous pouvez comme moi rajouter la possibilité de supprimer une tâche.

Pour cela j’utilise l’élément ion-sliding qui permet de faire glisser un item pour afficher des options et des boutons, je vous invite à consulter aussi la documentation d’Ionic: https://ionicframework.com/docs/api/item-sliding

J’intègre donc mon ion-item dans un ion-item-sliding, et j’aoute après celui-ci un option à la fin de mon item, pour afficher le bouton icône supprimé:

<ion-card *ngFor="let task of tasks">
  <ion-item-sliding>
    <ion-item lines="none">
      <ion-checkbox (ionChange)="changeCheckState(task)" color="success" [(ngModel)]="task.checked" slot="start"></ion-checkbox>
      <ion-label>
        <h2 *ngIf="!task.checked">{{ task.text }}</h2>
        <h2 *ngIf="task.checked" style="text-decoration:line-through;">{{ task.text }}</h2>
        <p>{{ task.hour }}</p>
      </ion-label>
    </ion-item>
    <ion-item-options side="end">
      <ion-item-option color="danger" (click)="deleteTask(task)">
        <ion-icon name="trash" slot="icon-only"></ion-icon>
      </ion-item-option>
    </ion-item-options>
  </ion-item-sliding>
</ion-card>

Ce bouton est associé à la fonction deleteTask() et lui transmet les informations de la tâche sélectionné, notamment pour récupérer sa clé Firebase.

deleteTask(task: any) {
	this.afDB.list('Tasks/').remove(task.key);
}

Nous utilisons ensuite la fonction remove de AngularFire pour supprimer l’item à la clé spécifié de notre base de données Firebase.

La dernière fonctionnalité à développer dans notre application concerne l’affichage de nos tâches quand elles sont terminées.

On souhaite notamment barrer le contenu de cette tâche lorsqu’on la coché, pour cela c’est très simple.

On créé deux titre h2 avec le même contenu, avec l’affichage de l’un ou de l’autre en fonction de la valeur du champ checked.

<h2 *ngIf="!task.checked">{{ task.text }}</h2>
<h2 *ngIf="task.checked" style="text-decoration:line-through;">{{ task.text }}</h2>

On ajoute simplement à la deuxième possibilité la propriété CSS pour barrer le texte tout simplement.

Ionic Todolist Firebase