Comment CRUD en Angular + Firebase Firestore

CRUD – Create, Read, Update, Delete – les quatre saint graal des actions de base de données. Ce sont les seules choses dont vous aurez jamais besoin pour faire quelque chose de significatif avec votre base de données. Bien sûr, vous pouvez augmenter la complexité des requêtes, mais à la fin de la journée, tout se résume à ces quatre actions.

Firebase est un système basé sur le cloud appartenant à Google qui est livré complet avec des crochets API, un espace de stockage de fichiers, un système d’authentification et des capacités d’hébergement. C’est un système très sous-estimé qui devrait être utilisé davantage pour le prototypage et le développement rapide d’applications.

Si vous voulez démarrer une application web progressive mais que vous n’avez pas l’expérience du backend pour mettre en place des serveurs, créer des API et traiter avec des bases de données, alors Firebase fait une option fantastique pour les développeurs frontaux qui peuvent se sentir isolés et embourbés par la colline massive d’informations qu’ils doivent traiter pour même mettre leur application en marche.

Ou si vous êtes simplement à court de temps, Firebase peut réduire vos heures de développement presque de moitié afin que vous puissiez vous concentrer sur l’expérience utilisateur et la mise en œuvre de ces flux IU. Il est également assez flexible pour migrer hors de votre application frontale et utiliser une base de données différente si nécessaire.

Voici un guide rapide sur la façon de mettre en œuvre des actions CRUD avec Angular et Firebase.

C’est une application de commande de café bare bones où vous pouvez ajouter des commandes (créer), lister les commandes de la base de données (lire), marquer la commande comme terminée (mettre à jour) et supprimer une commande (supprimer).

Le but de ce tutoriel est de vous aider à démarrer avec Firebase Firestore et de voir comment il est facile de se connecter et de démarrer sur le service appartenant à Google. Ce n’est pas une publicité pour Google (je ne reçois aucun kickback de leur part pour cela) mais simplement une illustration de la façon dont Angular joue avec la base de données.

L’application que nous allons faire n’est pas parfaite. Il manque des choses comme la validation des données et un million de fonctionnalités possibles que je peux aussi ajouter. Mais ce n’est pas le sujet. Le point est de mettre en place dans Angular aussi rapidement que possible et de le faire fonctionner avec une base de données en direct.

Alors, assez de l’intro – voici le code walk through.

La configuration initiale

Mettez en place votre application Angular via le CLI Angular. Si vous n’avez pas encore Angular CLI, vous pouvez en savoir plus à ce sujet ici.

En bref, il suffit d’exécuter ces commandes dans votre terminal dans le répertoire où vous voulez que votre app Angular se trouve. Voici les commandes et ce qu’elles font.

npm install -g @angular/cli

Installe Angular CLI sur votre terminal si vous ne l’avez pas déjà.

ng new name-of-app-here

Cela créera un nouveau projet Angular en utilisant la dernière version d’Angular disponible.

cd name-of-app-here

Lorsque vous créez un nouveau projet via Angular CLI, il créera un nouveau dossier de projet pour vous. cd vous emmènera dans ce dossier via le terminal.

ng serve

Ceci va démarrer et exécuter votre projet Angular.

Setting up Angular

Nous allons créer 3 nouvelles parties au total pour cette application Angular – commandes, order-list et shared/ordersService. Les deux premières sont des composants qui contiendront l’interface de l’app et le service shared/orders qui gardera tous les appels API Firebase ensemble.

Pour créer les fichiers nécessaires, exécutez les commandes suivantes :

ng g c orders

g signifie générer et c signifie composant. La dernière partie de la commande est le nom de votre fichier, qui pour le cas ci-dessus s’appelle commandes. Vous pouvez également utiliser ng generate component orders pour obtenir le même effet.

Créer un autre composant pour order-list en utilisant la commande suivante.

ng g c order-list

Et enfin, pour le service, utilisez s au lieu de c comme ci-dessous:

ng g s shared/orders

Cela créera un fichier orders.service.ts dans un dossier nommé shared. Assurez-vous d’ajouter orders.service.ts dans app.module.ts car cela n’est pas fait pour vous automatiquement comme les composants. Vous pouvez le faire via import et en l’ajoutant à la liste providers comme ceci:

import { OrdersService } from "./shared/orders.service";
...
providers:
...

The CSS

Pour ce tutoriel, nous allons utiliser Materialize CSS pour que notre application finale ait un meilleur aspect que le css par défaut. Ce n’est pas nécessaire et vous pouvez utiliser n’importe quel framework CSS ou votre propre CSS personnalisé si vous le souhaitez. Vous pouvez consulter les détails de Materialize CSS ici.

Nous allons également utiliser les icônes matérielles de Googles comme boutons pour marquer la commande de café comme terminée ou supprimer la commande.

Une façon de mettre cela en œuvre est d’avoir le code ci-dessous juste au-dessus de la balise </head> dans votre fichier index.html situé dans le dossier src.

<!-- Compiled and minified Materialize CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!-- Compiled and minified Materialize JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script><!-- Google Material Icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />

Le code initial de la vue Angular

En app.component.html, supprimez tout le code de démarrage. Nous allons utiliser notre propre contenu pour cela.

Nous allons accrocher le composant que nous venons de créer et les afficher à l’écran en utilisant les sélecteurs app-orders et app-order-list. Pour ce faire, nous écrivons le code ci-dessous :

<div class="container">
<div class="row">
<app-orders class="col s6"></app-orders>
<app-order-list class="col s6"></app-order-list>
</div>
</div>

Les classes container, row, col et s6 font partie du système de grille CSS de Materialize. Toutes les classes que vous verrez dans la suite de ce tutoriel sont issues de Materialize CSS, sauf mention contraire.

Mise en place du formulaire

Pour mettre en place des formulaires, importez ReactiveFormsModule dans app.module.ts et n’oubliez pas de l’importer dans le tableau imports.

import { ReactiveFormsModule } from "@angular/forms";

A l’intérieur de orders.service.ts, importez FormControl et FormGroup de @angular/formset créez un nouveau formulaire à l’extérieur de constructor où vous pouvez définir les propriétés du formulaire comme ci-dessous:

import { FormControl, FormGroup } from "@angular/forms";
...
...export class OrdersService {
constructor() {}
form = new FormGroup({
customerName: new FormControl(''),
orderNumber: new FormControl(''),
coffeeOrder: new FormControl(''),
completed: new FormControl(false)
})
}

Nous utiliserons ces valeurs pour les stocker dans Firebase un peu plus tard dans ce tutoriel.

Utilisation du formulaire à l’intérieur d’un composant

import la classe OrdersService dans votre composant afin que vous puissiez utiliser l’objet à l’intérieur de votre composant et ensuite créer un objet de la classe à l’intérieur du constructor.

import { OrdersService } from "../shared/orders.service";
...
constructor(private ordersService:OrdersService){}

À l’intérieur de votre orders.component.html utilisez la directive formGroup pour référencer l’objet formulaire créé dans OrdersService. Chaque formControlName référence les noms que nous avons utilisés dans la formGroup créée à l’intérieur de la classe OrdersService. Cela permettra au contrôleur associé d’utiliser les variables tapées dans le formulaire. Voir le code ci-dessous:

<form ="this.ordersService.form">
<input placeholder="Order Number"
formControlName="orderNumber"
type="text"
class="input-field col s12">
<input placeholder="Customer Name"
formControlName="customerName"
type="text"
class="input-field col s12">
</form>

Dans le orders.component.ts, nous allons mettre en place un tableau hors café pour boucler sur notre orders.component.html. En théorie, vous pourriez également configurer cela à l’intérieur de votre base de données Firestore, faire un appel à la collection et ensuite l’utiliser. Mais pour des raisons de longueur, nous allons le configurer comme un tableau local. Dans votre classe OrdersComponent, configurez le tableau suivant :

coffees = ;

Dans vos balises orders.component.html et <form>, bouclez-le en utilisant *ngFor avec un gestionnaire d’action (click) pour ajouter de nouveaux cafés à votre commande. Nous allons afficher la liste de commande juste en dessous avec la possibilité de supprimer un café individuel comme suit :

<button class="waves-effect waves-light btn col s4" 
*ngFor="let coffee of coffees"
(click)="addCoffee(coffee)">
{{coffee}}
</button><ul class="collection">
<li *ngFor="let coffee of coffeeOrder">
<span class="col s11"> {{ coffee }} </span>
<a class="col s1" (click)="removeCoffee(coffee)">x</a>
</li>
</ul>

À l’intérieur de orders.component vous créez un tableau vide pour loger la commande de café, utilisez la fonction addCoffee() pour ajouter de nouveaux cafés, et removeCoffee() pour supprimer une boisson de votre liste de commande.

coffeeOrder = ;addCoffee = coffee => this.coffeeOrder.push(coffee);removeCoffee = coffee => {
let index = this.coffeeOrder.indexOf(coffee);
if (index > -1) this.coffeeOrder.splice(index, 1);
};

Gestion de la soumission du formulaire

Ajoutez une entrée Soumettre la commande à l’intérieur et au bas des balises <form> et ajoutez le onSubmit() à un gestionnaire de clic comme ci-dessous:

<form ="this.ordersService.form" (ngSubmit)="onSubmit()"> ...
<button
class="waves-effect waves-light btn col s12"
(click)="onSubmit()">
Submit
</button>
</form>

Créez une onSubmit fonction vide dans votre orders.component pour l’intérim. Nous y ajouterons bientôt la gestion des événements. À ce stade, votre formulaire devrait être prêt à aller pour se connecter à votre base de données Firebase.

Mise en place du composant de liste

Maintenant, nous avons juste besoin d’un espace pour afficher nos commandes de café de la base de données. Pour l’instant, nous allons juste mettre en place le html échafaudage.

Naviguez vers votre order-list.component.html et créez un tableau avec 3 titres et 5 cellules de données. Les 3 premières cellules de données contiendront les valeurs tirées de la base de données et les 2 dernières contiendront une fonctionnalité supplémentaire qui vous permettra de marquer la commande comme complète ou de supprimer la commande.

Configuration de Firebase

Allez dans votre console Firebase et ajoutez un nouveau projet.

Cliquez sur ‘Add Project’ pour créer un nouveau projet.

Ajoutez un nom de projet, acceptez les termes et conditions et cliquez sur créer le projet.

Donnez un nom à votre projet et acceptez les termes de contrôleur-contrôleur afin de créer un projet.

Lorsque votre projet Firebase a été configuré, vous verrez quelque chose comme ceci.

Créer une base de données en sélectionnant Database sur le panneau latéral (situé sous Develop) puis cliquez sur Create Database sous la bannière Cloud Firestore.

Cliquez sur ‘Create database’

Sélectionnez start in test mode pour les règles de sécurité. Vous pouvez le modifier plus tard.

N’oubliez pas de garder vos informations d’identification sur votre machine locale uniquement pour des raisons de sécurité.

Vous obtiendrez une base de données Firestore vide comme ceci.

Connexion de Firebase Firestore à Angular

Pour connecter votre application Angular à Firebase, vous allez devoir installer les paquets firebase et @angular/fire. Cela vous donnera accès à AngularFireModule et AngularFirestoreModule. Utilisez la commande suivante dans votre terminal pour les installer.

npm i --save firebase @angular/fire

Implémentation des connecteurs

Retournez à votre console web Firebase et récupérez les détails de configuration à utiliser dans votre application Angular. Ceci est situé sur votre page de présentation du projet. Cela ressemble à quelque chose comme ceci:

Vous devrez utiliser vos propres informations d’identification. La configuration ci-dessus ne fonctionnera pas pour vous.

Copiez la section surlignée du code, naviguez vers votre fichier environment.ts (situé dans le dossier environments) et collez les détails de la configuration à l’intérieur de l’objet environment comme firebaseConfig. Voir l’exemple ci-dessous:

export const environment = {
production: false,
firebaseConfig: {
apiKey: "xxx",
authDomain: "xxxx.firebaseapp.com",
databaseURL: "https://xxxx.firebaseio.com",
projectId: "xxxx",
storageBucket: "xxxx.appspot.com",
messagingSenderId: "xxxxx"
}
};

Importez les paquets que vous avez installés plus tôt et le fichier environment.ts dans votre app.module.ts.Vous devrez initialiser le AngularFireModule avec le firebaseConfig dont vous venez de faire la configuration. Voir l’exemple ci-dessous :

import { environment } from "src/environments/environment";
import { AngularFireModule } from "@angular/fire";
import { AngularFirestoreModule } from "@angular/fire/firestore";
...
@NgModule({
...
imports:
...
})

Mise en place de Firestore dans un service

Importez AngularFirestore dans votre fichier orders.service.ts et déclarez-le dans le constructeur pour que votre service le connaisse.

...
import { AngularFirestore } from '@angular/fire/firestore';
...
export class OrdersService {
constructor( private firestore: AngularFirestore ) {}
...
}

Maintenant vous êtes prêt à commencer la partie CRUD de ce tutoriel Angular + Firebase Firestore.

C est pour Create

Afin de créer un nouvel enregistrement dans votre toute nouvelle base de données Firestore, vous allez devoir appeler .add() . Nous allons le faire à l’intérieur du fichier orders.service.ts.

Pour ce faire, vous devrez spécifier le nom collection et les données que vous voulez pousser vers la base de données. Dans notre cas, il s’agit de coffeeOrders .

Le code d’exemple ci-dessous utilise une promesse pour renvoyer l’appel Firebase et vous laisse ensuite décider de ce que vous voulez faire après que tout soit terminé.

...
createCoffeeOrder(data) {
return new Promise<any>((resolve, reject) =>{
this.firestore
.collection("coffeeOrders")
.add(data)
.then(res => {}, err => reject(err));
});
}
...

Pour appeler cette fonction dans votre composant, naviguez vers orders.component.ts et à l’intérieur de la fonction onSubmit() et du gestionnaire d’action, faites un appel le createCoffeeOrder() à travers ordersService.

L’exemple ci-dessous effectue un certain traitement des données en mappant le tableau coffeeOrder à la valeur du formulaire coffeeOrder. J’ai également créé une variable data à des fins de déstructuration (ainsi que pour ne pas avoir à passer un nom massivement long dans createCoffeeOrder()).

...
onSubmit() {
this.ordersService.form.value.coffeeOrder = this.coffeeOrder;
let data = this.ordersService.form.value;
this.ordersService.createCoffeeOrder(data)
.then(res => {
/*do something here....
maybe clear the form or give a success message*/
});
}
...

Et viola ! Vous avez maintenant créé un enregistrement de votre application Angular localhost vers votre base de données Firestore.

R est pour Read

Afin d’afficher les données de vos commandes de café, vous allez avoir besoin d’une fonction read dans votre orders.service.ts. L’exemple de code suivant vous donnera toutes les valeurs stockées dans votre collection coffeeOrders.

...
getCoffeeOrders() {
return
this.firestore.collection("coffeeOrders").snapshotChanges();
}
...

Pour utiliser cette fonction, vous devrez l’appeler depuis votre orders-list.component.ts . Vous pouvez le faire en important le OrdersService dans le fichier et l’initialiser dans le constructor.

...
import { OrdersService } from "../shared/orders.service";
...export class OrderListComponent implements OnInit {
constructor(private ordersService:OrdersService){}
...
}

Créer une fonction pour contenir votre appel et l’initialiser sur le ngOnInit() pour l’appeler lorsque la vue est chargée pour la première fois. Créez une variable coffeeOrders pour mapper les résultats retournés de votre base de données via subscribe(). Nous allons l’utiliser pour itérer et afficher dans order-list.component.html

...
ngOnInit() {this.getCoffeeOrders();}
... coffeeOrders; getCoffeeOrders = () =>
this.ordersService
.getCoffeeOrders()
.subscribe(res =>(this.coffeeOrders = res));...

Pour utiliser coffeeOrders dans votre order-list.component.html , utilisez *ngFor pour boucler sur le tableau retourné. Vous devez également faire un peu d’inception et faire une autre boucle pour la partie coffeeOrder pour obtenir votre liste de cafés pour chaque client. Il y a des façons plus efficaces de faire cela mais pour ce tutoriel, voyez le code d’exemple ci-dessous :

...
<tbody>
<tr *ngFor="let order of coffeeOrders">
<td>{{ order.payload.doc.data().orderNumber }}</td>
<td>{{ order.payload.doc.data().customerName }}</td>
<td><span
*ngFor="let coffee of order.payload.doc.data().coffeeOrder">
{{ coffee }}
</span>
</td>
</tr>
</tbody>
...

Et voilà, vous l’avez. Vous avez maintenant accroché des capacités de lecture à votre application Angular.

U est pour Update

Disons que nous voulons être en mesure de marquer la commande de café comme complète dans la base de données et faire quelque chose à l’article de ligne basé sur le changement. Parce que snapshot() garde la trace de tous les changements qui se produisent, vous n’avez pas besoin de faire un suivi ou une interrogation de la base de données.

Nous allons créer une autre cellule de données dans notre table avec une icône ‘check’ de Google Materialize Icons et la connecter à un événement (click) qui appellera la fonction markCompleted() dans votre order-list.component.ts. Nous allons également passer dans l’ordre particulier pour cette boucle.

Nous allons définir un attribut avec la valeur completed à la cellule de données afin qu’elle puisse déterminer dynamiquement si nous voulons avoir l’icône ‘check’ à l’affichage. Nous avons initialement défini cette valeur comme false lorsque nous avons créé le formulaire dans orders.service.ts .

...
<td ="order.payload.doc.data().completed"
(click)="markCompleted(order)">
<i class="material-icons">check</i>
</td>
...

Inside order-list.component.ts , créer la fonction markCompleted() qui utilise le data injecté pour passer à une fonction appelée updateCoffeeOrder() dans orders.service.ts.

...
markCompleted = data =>
this.ordersService.updateCoffeeOrder(data);
...

Inside orders.service.ts créer la fonction de manipulation. Cette fonction va se connecter et appeler votre base de données Firestore en fonction de la collection sélectionnée et de l’id du document. Nous savons déjà que notre collection s’appelle coffeeOrders et nous pouvons trouver l’id du document basé sur les paramètres passés dans l’appel de la fonction du composant.

.set() définira l’enregistrement spécifique avec les données que vous avez passées. .set() prend dans deux paramètres – vos données et un objet de paramètres. Si vous utilisez merge: true, alors cela signifie que vous ne mettez à jour que la paire valeur-clé passée plutôt que de remplacer le document entier avec ce que vous avez passé.

...
updateCoffeeOrder(data) {
return
this.firestore
.collection("coffeeOrders")
.doc(data.payload.doc.id)
.set({ completed: true }, { merge: true });
}
...

Maintenant, lorsque vous cliquez sur l’icône ‘vérifier’ dans votre vue, cela mettra à jour votre base de données et disparaîtra parce que votre attribut est maintenant défini à true.

D est pour Delete

Pour l’action finale, nous allons tout configurer de manière similaire au processus de mise à jour – mais au lieu de mettre à jour l’enregistrement, nous allons le supprimer.

Mettez en place une autre cellule de données avec un gestionnaire d’événement de clic qui appelle une fonction deleteOrder(). Nous allons passer l’instance de la donnée order dans la boucle lorsque l’icône ‘delete_forever’ est cliquée. Vous en aurez besoin pour l’identifiant du document. Voir le code ci-dessous à titre d’exemple :

...
<td ="order.payload.doc.data().completed"
(click)="deleteOrder(order)">
<i class="material-icons">delete_forever</i>
</td>
...

Dans votre order-list.component.ts, créez la fonction associée qui appelle une fonction deleteCoffeeOrder() dans votre orders.service.ts .

...
deleteOrder = data => this.ordersService.deleteCoffeeOrder(data);
...

Dans votre orders.service.ts, créez la fonction deleteCoffeeOrder() et utilisez le data injecté pour savoir quel est l’id du document. Comme pour update, vous devez connaître à la fois le nom de la collection et l’id du document pour identifier correctement l’enregistrement que vous voulez supprimer. Utilisez .delete() pour indiquer à Firestore que vous voulez supprimer l’enregistrement.

...
deleteCoffeeOrder(data) {
return
this.firestore
.collection("coffeeOrders")
.doc(data.payload.doc.id)
.delete();
}
...

Maintenant, lorsque vous cliquez sur l’icône ‘delete_forever’, votre application Angular se déclenchera et indiquera à Firestore de supprimer l’enregistrement spécifique. Votre enregistrement disparaîtra de la vue lorsque le document spécifié sera supprimé.

Application finale

Vous pouvez trouver le dépôt Github pour l’ensemble du projet de travail ici. Vous devrez créer votre propre base de données Firebase et la brancher vous-même en mettant à jour les fichiers de configuration. Le code lui-même n’est pas parfait mais je l’ai gardé très minimal afin que vous puissiez voir comment Firestore fonctionne dans une application Angular sans avoir à parcourir une jungle de code.

J’ai essayé de condenser le tutoriel vers le bas autant que possible sans manquer aucun détail. C’était un mélange difficile mais comme vous pouvez le voir ci-dessus, une grande partie est principalement le code Angular et pas beaucoup Firestore. Firebase Firestore peut faire des requêtes beaucoup plus complexes mais pour les besoins de la démonstration, je l’ai gardé simple. En théorie, si votre structure de données reste la même, vous pouvez échanger Firestore et mettre un ensemble différent de connexions API avec un remaniement minimal requis.

Mots finaux

J’aime personnellement Firebase en raison de la facilité avec laquelle il est possible de créer rapidement des projets prêts pour la production sans avoir à créer un backend entier et un serveur pour le soutenir. En termes de coût, ce n’est pas trop mauvais et les projets de test sont gratuits pour démarrer (et ils ne vous font pas entrer les détails de votre carte de crédit jusqu’à ce que vous soyez prêt à changer de plan). Dans l’ensemble, il a fallu plus de temps pour créer le formulaire et l’interface entourant l’application que pour connecter l’application à Firestore. Je n’ai pas ajouté la validation du formulaire à ce tutoriel en raison de sa longueur, mais je créerai un autre post à ce sujet à l’avenir.

Laisser un commentaire