Comment créer un chat dans Ionic avec Firebase ? Comment créer une application de messagerie très simple avec Ionic, Facebook Login et Firebase ?

Les applications de chat sot de plus en plus populaires dans le monde, et les fonctionnalités de messagerie sont maintenant intégrés dans un grand nombre d’applications (Vinted, Instagram, Amazon Alexa, Leboncoin, etc).

Aujourd’hui je vous propose un tuto Ionic complet pour créer votre application de chat avec Ionic. Cette fonctionnalité peut être ajouté à n’importe quelle application existence, tant qu’elle est connectée à Firebase.

Nous allons voir différentes étapes pour créer cette application chat:

  • Les différentes méthodes de connexion pour Firebase
  • Tester et récupérer l’ID de l’utilisateur
  • Envoyer un message
  • Afficher les messages
  • Diviser les messages perso et des autres

Comment choisir une méthode de connexion pour votre chat Ionic avec Firebase ?

Pour commencer il nous faut une méthode de connexion pour identifier nos utilisateurs. Heureusement Firebase en propose une dizaine dans sa gestion de l’authentification.

Vous pouvez par exemple choisir l’authentification mail et mot de passe, téléphone ou bien par Google.

Les méthodes de connexion de Firebase
Les méthodes de connexion de Firebase

Pour des raisons des simplicité, j’ai choisi de reprendre l’authentification par Facebook qui est selon moi la plus simple et la plus efficace à prendre en main.

L’avantage de Facebook Login est que nous récupérons le nom complet de l’utilisateur et sa photo de profil une fois connecté.

Pour cette raison, vous devez avoir suivi le tutoriel sur la connexion avec Facebook: https://drissas.com/facebook-login-ionic/

Prenez soin d’ajouter un bouton de déconnexion dans votre page Ionic, vous permettre à vos utilisateurs de se déconnecter en cas de besoin.

Voici la fonction de déconnexion logout():

logout() {
	this.afAuth.auth.signOut();
	this.connected = false;
}

Cette fonction déconnecte en premier lieu l’utilisateur avec la fonction signOut() du module AngularFireAuth puis modifie la valeur de la variable connected.

La variable booléenne connected nous permet de stocker l’état de connexion de l’utilisateur, et d’afficher en fonction certain élément de notre page HTML.

Si il est connecté, on lui affiche un bouton de déconnexion, s’il n’est pas connecté, on lui affiche un bouton de connexion.

Cette technique permet de conserver la même page pour gérer plusieurs fonctionnalités.

Ainsi que le bouton HTML de déconnexion:

<ion-buttons slot="end" *ngIf="connected">
  <ion-button color="dark" (click)="logout()">
    <ion-icon slot="icon-only" name="log-out"></ion-icon>
  </ion-button>
</ion-buttons>

Vous pouvez placer ce bouton à la suite de votre <ion-title> dans le <ion-header> de votre page.

<ion-header>
  <ion-toolbar>
    <ion-title>
      Chat
    </ion-title>
    <ion-buttons slot="end" *ngIf="connected">
      <ion-button color="dark" (click)="logout()">
        <ion-icon slot="icon-only" name="log-out"></ion-icon>
      </ion-button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>

De cette manière, on affiche à notre utilisateur le bouton de déconnexion que lorsqu’il est bien connecté.

Vous devez absolument avoir une méthode de connexion valide pour gérer le chat Ionic avec Firebase, cela nous permettra d’identifier nos utilisateurs.

Pour le moment vous devez juste avoir le bouton de connexion Facebook dans votre ion-content et le bouton de déconnexion dans le header.

Comment tester la connexion de l’utilisateur dans Ionic avec Firebase ?

Passons maintenant à la deuxième étape, dans laquelle nous testons l’état de connexion de l’utilisateur. Non seulement nous allons vérifier qu’il est connecté, mais nous allons également récupérer son identifiant Firebase.

C’est cet identifiant unique généré par Firebase qui va nous permettre de gérer l’envoi des messages par la suite, que chaque message soit associé à un utilisateur.

C’est vraiment la base de toute application à interface sociale. Nous créons pour commencer deux variables:

  • connected: pour stocker l’état de connexion (true ou false)
  • userId: pour stocker l’identifiant unique de l’utilisateur
connected = false;
userId: string;

Ensuite, nous créons un script nous tester l’état de connexion de l’utilisateur avec le plugin AngularFireAuth.

Pour cela nous exécutons la sous-fonction authState qui comme son nom l’indique renvoie l’état de connexion de l’utilisateur, et en cas de connexion nous renvoie ses informations.

Ces informations sont renvoyées dans l’objet auth, qui s’il est vide signifie que l’utilisateur n’est pas connecté, sinon que l’utilisateur est bien connecté et que l’on peut lire ses informations comme son identifiant avec auth.uid:

this.afAuth.authState.subscribe(auth => {
	if (!auth) {
		console.log('non connecté');
	} else {
		console.log('UserId: ' + auth.uid);
		this.connected = true;
		this.userId = auth.uid;
		this.getMessages();
	}
});

Si l’utilisateur est bien connecté, on affiche dans la console son identifiant, on le stocke dans la variable userId, on indique que le l’utilisateur est bien connecté avec la variable connected = true.

Enfin on exécute la fonction getMessages() et getCurrentUserData() que nous définirons par la suite.

En revanche si l’utilisateur n’est pas connecté, on affiche simplement dans la console ‘non connecté‘. On aurait pu affecter à la variable connected false, mais comme c’est sa valeur par défaut il nous suffit de ne pas la modifier.

Encore une fois, cette étape de vérification de l’état de connexion est indispensable à toute application sociale. Vous devez d’ailleurs exécuter ce code dans la plupart de vos pages, car si l’utilisateur n’est pas connecté il faut le rédiger vers la page de connexion par exemple ?

Comment envoyer un message depuis le chat Ionic dans Firebase ?

Passons à l’une des partie les plus intéressante de l’application chat avec Ionic et Firebase. Nous allons créer un formulaire d’envoi de message en bas de notre page.

Pour commencer nous utilisons la balise <ion-footer> qui positionnera son contenu en bas de l’écran, y compris si le clavier de l’utilisateur est ouvert.

Nous ajoutons la condition *ngIf= »connected » pour n’afficher ce formulaire que dans le cas où l’utilisateur est connecté:

<ion-content>[...]</ion-content>

<ion-footer *ngIf="connected">
 
</ion-footer>

Ensuite nous utilisons les balise <ion-grid>, <ion-row> et <ion-col> pour créer une apparence de formulaire de messagerie.

La première colonne qui contient notre <ion-input> (là où l’utilisateur entre son message) prend une largeur de 10/12 tandis que la deuxième qui contient le bouton d’envoi a une largeur de 2/12:

<ion-footer *ngIf="connected">
  <ion-grid>
    <ion-row>
      <ion-col size="10">
        <ion-input type="text" placeholder="Entrez votre message"></ion-input>
      </ion-col>
      <ion-col size="2">
        <ion-button shape="full">
          <ion-icon name="paper-plane"></ion-icon>
        </ion-button>
      </ion-col>
    </ion-row>
  </ion-grid>
</ion-footer>

Enfin pour que notre application ressemble à une véritable application chat nous lui donnons quelques propriétés CSS. Ajoutez d’abord les classes « input-col » et « send-col » à vos deux colonnes HTML:

<ion-footer *ngIf="connected">
  <ion-grid>
    <ion-row>
      <ion-col size="10" class="input-col">
        <ion-input  type="text" placeholder="Entrez votre message"></ion-input>
      </ion-col>
      <ion-col size="2" class="send-col">
        <ion-button shape="full">
          <ion-icon name="paper-plane"></ion-icon>
        </ion-button>
      </ion-col>
    </ion-row>
  </ion-grid>
</ion-footer>

Voilà ensuite le CSS à ajouter à votre page, surtout pour modifier l’apparence du bouton d’envoi:

ion-grid {
	padding: 0px!important;
	border-top: solid 1px #d2cdcd;
}
.input-col {
	padding-left: 10px;
}
.send-col {
	padding: 0px!important;
}
.send-col ion-button {
	height: 100%!important;
	margin: 0px!important;
	border-radius: 0px !important;
}
.send-col button {
	border-radius: 0px !important;
}
.send-col ion-icon {
	font-size: 20px!important;
}

Concernant les derniers détails de notre formulaire, nous devons le rendre dynamique et l’associer à notre fichier TypeScript.

Ajouter [(ngModel)]= »messageText » à votre <ion-input> pour l’associer à la variable messageText:

<ion-input autocomplete="true" spellcheck="true" [(ngModel)]="messageText" type="text" placeholder="Entrez votre message" name="message"></ion-input>

Puis associer votre bouton HTML à la fonction sendMessage():

<ion-button shape="full" (click)="sendMessage()">
  <ion-icon name="paper-plane"></ion-icon>
</ion-button>

Votre formulaire et <ion-footer> doit maintenant ressembler à ça:

<ion-footer *ngIf="connected">
  <ion-grid>
    <ion-row>
      <ion-col size="10" class="input-col">
        <ion-input autocomplete="true" spellcheck="true" [(ngModel)]="messageText" type="text" placeholder="Entrez votre message" name="message"></ion-input>
      </ion-col>
      <ion-col size="2" class="send-col">
        <ion-button shape="full" (click)="sendMessage()">
          <ion-icon name="paper-plane"></ion-icon>
        </ion-button>
      </ion-col>
    </ion-row>
  </ion-grid>
</ion-footer>

Concluons sur la partie TypeScript de notre formulaire qui vous allez le voir est très simple.

Commençons pas déclarer une variable dans notre page, que nous appelons messageText est qui nous servira à conserver la valeur du message de l’utilisateur:

messageText: any;

Créons ensuite la fonction pour envoyer le message sur Firebase.

Pour cela rien de plus simple, on utilise le plugin AngularFireDatabase ainsi que la sous fonction « list » avec comme paramètre l’adresse de notre liste (‘Messages/) et comme deuxième fonction « push » pour lui ajouter du contenu:

sendMessage() {
	this.afDB.list('Messages/').push({
		userId: this.userId,
		text: this.messageText,
		date: new Date().toISOString()
	});
	this.messageText = '';
}

À la fin de notre fonction, nous réinitialisons la valeur de notre variable messageText qui vide instantanément notre champ message du formulaire.

Comment afficher les messages dans la conversation ?

Continuons avec l’affichage des messages de nos utilisateurs dans notre page. Nous allons d’abord traiter la partie TypeScript pour récupérer les messages puis la partie HTML pour les afficher.

Pour commencer, nous créons une variable de type tableau pour contenir tous les messages de la base de données Firebase:

public messages: any = [];

Ensuite nous créons la fonction pour parcourir notre tables Messages:

getMessages() {

}

D’abord nous utilisons le plugin AngularFireDatabase, ainsi que la sous fonction list, qui va nous permettre d’indiquer l’adresse exacte de notre base.

La sous fonction snapshotChanges avec comme paramètre ([‘child_added’]) nous permet de nous « abonner » à notre table et d’exécuter ce script à chaque ajout de données à notre table:

getMessages() {
	this.afDB.list('Messages/').snapshotChanges(['child_added'])
	.subscribe(actions => {
	
	});
}

Finalement on ajoute le paramètre suivant à notre requête dans la fonction list, pour lister les éléments (orderByChild) par leur date:

getMessages() {
	this.afDB.list('Messages/', ref => ref.orderByChild('date')).snapshotChanges(['child_added'])
	.subscribe(actions => {
		
	});
}

Ce que nous allons maintenant ajouter à l’intérieur de cette accolade va s’exécuter à chaque fois qu’un message est ajouté à notre table « Messages ».

On commence par initialiser la variables messages sous forme de tableau vide:

this.messages = [];

Puis nous parcourons l’objet renvoyé par la fonction AngularFireDatabase:

actions.forEach(action => {
  console.log('Message: ' + action.payload.exportVal().text);
});

À chaque message rencontré, on peut lui demander d’afficher son contenu texte, la date à laquelle il a été posté et l’identifiant de l’utilisateur.

Plutôt que de simplement les afficher, nous les ajoutons directement à notre variable messages qui contiendra à la fin tous les messages existant:

getMessages() {
	this.afDB.list('Messages/', ref => ref.orderByChild('date')).snapshotChanges(['child_added'])
	.subscribe(actions => {
		this.messages = [];
		actions.forEach(action => {
			this.messages.push({
				userId: action.payload.exportVal().userId,
				text: action.payload.exportVal().text,
				date: action.payload.exportVal().date
			});
		});
	});
}

La fonction getMessages() est désormais terminée et nous pouvons passer à la partie HTML.

Tout d’abord nous créons une boîte <div> pour contenir l’ensemble de nos messages. Nous lui ajoutons la condition*ngIf= »connected » pour n’afficher cette partie que si l’utilisateur est bien connecté.

<div class="stream" *ngIf="connected">

</div>

Ensuite nous ajoutons le contenu de cette boîte, qui consiste en une liste de <ion-item> qui contienne chacun le texte d’un message.

Pour cela nous effectuons une boucle pour parcourir tous les messages avec la propriété ngFor= »let message of messages »:

<div class="stream" *ngIf="connected">
	<ion-item lines="none" *ngFor="let message of messages">
		<p>{{ message.text }}</p>
	</ion-item>
</div>

Les messages de votre base de données devraient maintenant apparaître dans votre page. Vous pouvez également déjà tester l’actualisation des messages en direct en ajouter de nouveaux messages.

Comment filtrer les messages de votre conversation ?

Pour conclure ce chat Ionic Firebase, nous allons travailler sur une des fonctionnalités essentielles des chats et autres messagerie. Il s’agit de différencier ses propres messages de ceux des autres utilisateurs.

Étant donné que pour chaque message nous disposons de l’identifiant de d’utilisateur et que nous connaissant celui de l’utilisateur connecté nous pouvons comparer les deux.

Nous disposons donc de deux cas:

  • *ngIf= »message.userId != userId »: C’est le message d’un autre utilisateur
  • *ngIf= »message.userId == userId »: C’est l’un de mes messages

Nous créons donc deux contenus différents sous forme de badge (voir la documentation Ionic) qui vont prendre une couleur différente et se positionner en début ou en fin de ligne.

Si c’est un message d’un autre utilisateur:

<ion-badge text-wrap slot="start" color="light" *ngIf="message.userId != userId">{{ message.text }}</ion-badge>

Si c’est un message de l’utilisateur connecté:

<ion-badge text-wrap slot="end" color="primary" *ngIf="message.userId == userId">{{ message.text }}</ion-badge>

Voilà donc le résultat final de notre contenu HTML pour afficher tous les messages de la base de données et de notre chat:

<div class="stream" *ngIf="connected">
	<ion-item lines="none" *ngFor="let message of messages">
		<ion-badge text-wrap slot="start" color="light" *ngIf="message.userId != userId">{{ message.text }}</ion-badge>
		<ion-badge text-wrap slot="end" color="primary" *ngIf="message.userId == userId">{{ message.text }}</ion-badge>
	</ion-item>
</div>

Pour conclure, vous pouvez ajouter les propriétés CSS suivantes à vos messages:

.stream ion-item {
    min-height: fit-content !important;
    height: 51px;
}
ion-badge {
    padding: 10px!important;
    text-align: left;
    max-width: 80%;
}

Si vous ne l’avez pas encore fait, commencez au plus vite mon programme gratuit IONIC STARTER comme commencer rapidement avec Ionic.

Pour aller plus loin, commencez le programme IONIC FACILE et créez des applications incroyables pour bluffer vos utilisateurs et vos clients.

Vous pourrez alors créer une application chat avec partage de photos, conversation individuelles avec un unique utilisateur et d’autres fonctionnalités.