Come CRUD in Angular + Firebase Firestore

CRUD – Create, Read, Update, Delete – le quattro azioni del Santo Graal dei database. Sono le uniche cose di cui avrete bisogno per fare qualcosa di significativo con il vostro database. Certo, si può aumentare la complessità delle query, ma alla fine della giornata, tutto si riduce a queste quattro azioni.

Firebase è un sistema basato su cloud di proprietà di Google che è completo di ganci API, spazio di archiviazione dei file, sistema di autenticazione e capacità di hosting. È un sistema molto sottovalutato che dovrebbe essere utilizzato di più per la prototipazione e lo sviluppo rapido di applicazioni.

Se si desidera avviare un’applicazione web progressiva, ma non si ha l’esperienza di back-end per impostare i server, creare API e trattare con i database, allora Firebase è una fantastica opzione per gli sviluppatori front-end che possono sentirsi isolati e impantanati dalla massiccia collina di informazioni che devono elaborare anche solo per ottenere la loro applicazione attiva e funzionante.

O se siete semplicemente a corto di tempo, Firebase può tagliare le vostre ore di sviluppo quasi a metà in modo da potersi concentrare sull’esperienza dell’utente e sull’implementazione dei flussi UI. È anche abbastanza flessibile per migrare la tua applicazione front-end e utilizzare un database diverso, se necessario.

Qui c’è una guida rapida su come implementare azioni CRUD con Angular e Firebase.

Si tratta di un’applicazione per ordinare un caffè in cui è possibile aggiungere ordini (creare), elencare gli ordini dal database (leggere), segnare l’ordine come completato (aggiornare) e rimuovere un ordine (eliminare).

Lo scopo di questo tutorial è quello di aiutarvi a iniziare con Firebase Firestore e vedere quanto sia facile connettersi e iniziare a utilizzare il servizio di proprietà di Google. Questa non è una pubblicità per Google (non ricevo tangenti da loro per questo) ma semplicemente un’illustrazione di come Angular gioca con il database.

L’app che stiamo per fare non è perfetta. Ci sono cose che mancano come la validazione dei dati e un milione di possibili caratteristiche che posso anche aggiungere. Ma non è questo il punto. Il punto è impostare in Angular il più velocemente possibile e farlo funzionare con un database live.

Quindi, basta con l’introduzione – ecco il codice da seguire.

La configurazione iniziale

Imposta la tua app Angular tramite la CLI Angular. Se non avete già Angular CLI, potete saperne di più qui.

In breve, eseguite semplicemente questi comandi nel vostro terminale nella directory dove volete che si trovi la vostra app Angular. Ecco i comandi e cosa fanno.

npm install -g @angular/cli

Installa Angular CLI sul tuo terminale se non ce l’hai già.

ng new name-of-app-here

Questo creerà un nuovo progetto Angular usando l’ultima versione di Angular disponibile.

cd name-of-app-here

Quando crei un nuovo progetto tramite Angular CLI, creerà una nuova cartella di progetto per te. cd ti porterà in quella cartella tramite il terminale.

ng serve

Questo avvierà ed eseguirà il tuo progetto Angular.

Impostare Angular

Creeremo 3 nuove parti in totale per questa app Angular – orders, order-list e shared/ordersService. I primi due sono componenti che conterranno l’interfaccia dell’app e il servizio shared/orders che terrà insieme tutte le chiamate API di Firebase.

Per creare i file necessari, eseguire i seguenti comandi:

ng g c orders

g sta per generate e c sta per component. L’ultima parte del comando è il nome del vostro file, che nel caso di cui sopra si chiama ordini. Puoi anche usare ng generate component orders per ottenere lo stesso effetto.

Crea un altro componente per order-list usando il seguente comando.

ng g c order-list

E infine, per il servizio, usa s invece di c come sotto:

ng g s shared/orders

Questo creerà un file orders.service.ts in una cartella chiamata shared. Assicuratevi di aggiungere orders.service.ts in app.module.ts perché questo non viene fatto automaticamente per voi come i componenti. Puoi farlo tramite import e aggiungendolo alla lista providers in questo modo:

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

Il CSS

Per questo tutorial, useremo Materialize CSS per rendere la nostra applicazione finale migliore del css di default. Non è necessario e puoi usare qualsiasi framework CSS o il tuo CSS personalizzato se vuoi. Puoi controllare i dettagli di Materialize CSS qui.

Utilizzeremo anche le icone materiali di Google come pulsanti per segnare l’ordine del caffè come completato o per cancellarlo.

Un modo per implementare questo è quello di avere il codice qui sotto proprio sopra il tag </head> nel vostro file index.html situato nella cartella 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" />

Il codice iniziale della vista Angular

In app.component.html, eliminate tutto il codice iniziale. Useremo i nostri contenuti per questo.

Ci agganceremo al componente che abbiamo appena creato e li visualizzeremo sullo schermo usando i selettori app-orders e app-order-list. Per fare questo, scriviamo il codice qui sotto:

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

Le classi container, row, col e s6 fanno parte del sistema di griglia CSS Materialize. Tutte le classi che vedrai nel resto di questo tutorial sono di Materialize CSS, a meno che non sia menzionato diversamente.

Impostare il modulo

Per impostare i moduli, importa ReactiveFormsModule in app.module.ts e ricorda di importarlo nell’array imports.

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

Inserite orders.service.ts importate FormControl e FormGroup da @angular/formse create un nuovo modulo fuori dal constructor dove potete impostare le proprietà del modulo come segue:

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)
})
}

Useremo questi valori per memorizzarli in Firebase poco più avanti in questo tutorial.

Utilizzare il form all’interno di un componente

import la classe OrdersService nel tuo componente in modo da poter utilizzare l’oggetto all’interno del tuo componente e quindi creare un oggetto della classe all’interno del constructor.

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

Nella tua orders.component.html usa la direttiva formGroup per referenziare l’oggetto form creato in OrdersService. Ogni formControlName fa riferimento ai nomi che abbiamo usato nella formGroup creata all’interno della classe OrdersService. Questo permetterà al controller associato di utilizzare le variabili digitate nel modulo. Vedi il codice qui sotto:

<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>

Nella orders.component.ts, imposteremo un array di caffè per il looping sul nostro orders.component.html. In teoria, potreste anche impostare questo all’interno del vostro database Firestore, fare una chiamata alla collezione e poi usarla. Ma per motivi di lunghezza, lo imposteremo come un array locale. All’interno della tua classe OrdersComponent, imposta il seguente array:

coffees = ;

Nei tuoi tag orders.component.html e all’interno del tuo tag <form>, esegui un loop usando *ngFor con un gestore di azioni (click) per aggiungere nuovi caffè al tuo ordine. Visualizzeremo la lista dell’ordine proprio qui sotto con la possibilità di rimuovere i singoli caffè come segue:

<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>

Inside orders.component crei un array vuoto per ospitare l’ordine di caffè, usi la funzione addCoffee() per aggiungere nuovi caffè, e removeCoffee() per rimuovere una bevanda dalla lista dell’ordine.

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

Gestione dell’invio del modulo

Aggiungi un input Submit Order dentro e in fondo ai tag <form> e aggiungi il onSubmit() a un gestore di click come qui sotto:

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

Crea una funzione onSubmit vuota nel tuo orders.component per l’interim. Aggiungeremo presto la gestione degli eventi. A questo punto, il tuo modulo dovrebbe essere pronto a partire per agganciarsi al tuo database Firebase.

Impostare il componente elenco

Ora abbiamo solo bisogno di uno spazio per visualizzare i nostri ordini di caffè dal database. Per ora, ci limiteremo a impostare l’impalcatura html.

Passa al tuo order-list.component.html e crea una tabella con 3 titoli e 5 celle di dati. Le prime 3 celle dati conterranno i valori estratti dal database e le ultime 2 conterranno funzionalità extra che ti permetteranno di segnare l’ordine come completo o di cancellarlo.

Impostare Firebase

Vai alla tua console Firebase e aggiungi un nuovo progetto.

Clicca su ‘Add Project’ per creare un nuovo progetto.

Aggiungi un nome al progetto, accetta i termini e le condizioni e clicca su create project.

Dai un nome al tuo progetto e accetta i termini del controller-controller per creare un progetto.

Quando il tuo progetto Firebase è stato impostato, vedrai qualcosa come questo.

Crea un database selezionando Database nel pannello laterale (situato sotto Develop) e poi clicca su Create Database sotto il banner Cloud Firestore.

Clicca su ‘Create database’

Seleziona start in test mode per le regole di sicurezza. Puoi modificarle in seguito.

Ricorda di tenere le tue credenziali sulla tua macchina locale solo per motivi di sicurezza.

Ottieni un database Firestore vuoto come questo.

Collegare Firebase Firestore ad Angular

Per collegare la tua app Angular a Firebase, dovrai installare i pacchetti firebase e @angular/fire. Questo vi darà accesso a AngularFireModule e AngularFirestoreModule. Usa il seguente comando nel tuo terminale per installarli.

npm i --save firebase @angular/fire

Implementazione dei connettori

Torna alla tua console web Firebase e prendi i dettagli di configurazione da usare nella tua app Angular. Questo si trova nella tua pagina di panoramica del progetto. Assomiglia a questo:

Devi usare le tue credenziali. La configurazione di cui sopra non funzionerà per te.

Copia la sezione evidenziata del codice, naviga al tuo file environment.ts (situato all’interno della cartella environments) e incolla i dettagli della configurazione all’interno dell’oggetto environment come firebaseConfig. Vedi sotto per esempio:

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"
}
};

Importa i pacchetti che hai installato prima e il file environment.ts nel tuo app.module.ts.Dovrai inizializzare il AngularFireModule con il firebaseConfig per cui hai appena fatto la configurazione. Vedi l’esempio qui sotto:

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

Impostare Firestore in un servizio

Importa AngularFirestore nel tuo file orders.service.ts e dichiaralo nel costruttore così il tuo servizio lo conosce.

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

Ora sei pronto per iniziare la parte CRUD di questo tutorial Angular + Firebase Firestore.

C sta per Create

Per creare un nuovo record nel tuo nuovo database Firestore, dovrai chiamare .add() . Lo faremo all’interno del file orders.service.ts.

Per fare questo, dovrai specificare il nome collection e quali dati vuoi inviare al database. Nel nostro caso, è coffeeOrders.

Il codice di esempio qui sotto usa una promessa per restituire la chiamata a Firebase e poi ti lascia decidere cosa vuoi fare dopo che tutto è finito.

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

Per chiamare questa funzione nel tuo componente, vai a orders.component.ts e all’interno della funzione onSubmit() e del gestore dell’azione, fai una chiamata a createCoffeeOrder() attraverso ordersService.

L’esempio qui sotto fa qualche elaborazione dei dati mappando l’array coffeeOrder al valore del modulo coffeeOrder. Ho anche creato una variabile data per scopi di destrutturazione (oltre a non dover passare un nome enormemente lungo in 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*/
});
}
...

E viola! Ora hai creato un record dalla tua app Angular localhost al tuo database Firestore.

R sta per Read

Per visualizzare i dati dei tuoi ordini di caffè, avrai bisogno di una funzione di lettura nel tuo orders.service.ts. Il seguente esempio di codice ti darà tutti i valori memorizzati nella tua collezione coffeeOrders.

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

Per usare questa funzione, dovrai chiamarla dal tuo orders-list.component.ts . Potete farlo importando la OrdersService nel file e inizializzarla nella constructor.

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

Create una funzione che contenga la vostra chiamata e inizializzatela sulla ngOnInit() per chiamarla quando la vista viene caricata per la prima volta. Create una variabile coffeeOrders per mappare i risultati restituiti dal vostro database tramite subscribe(). Lo useremo per iterare e visualizzare in order-list.component.html

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

Per usare coffeeOrders nel tuo order-list.component.html , usa *ngFor per fare un ciclo attraverso l’array restituito. Devi anche fare un po’ di inception e fare un altro ciclo per la parte coffeeOrder per ottenere la tua lista di caffè per ogni cliente. Ci sono modi più efficienti per farlo, ma per questo tutorial, vedi il codice di esempio qui sotto:

...
<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>
...

Ed ecco fatto. Ora avete collegato le capacità di lettura alla vostra applicazione Angular.

U sta per Update

Diciamo che vogliamo essere in grado di segnare l’ordine del caffè come completo nel database e fare qualcosa alla voce di linea in base al cambiamento. Poiché snapshot() tiene traccia di ogni cambiamento che avviene, non c’è bisogno di fare alcun monitoraggio o polling al database.

Creeremo un’altra cella dati nella nostra tabella con un’icona ‘check’ da Google Materialize Icons e la agganceremo ad un evento (click) che chiamerà la funzione markCompleted() nel tuo order-list.component.ts. Passeremo anche l’ordine particolare per questo ciclo.

Imposteremo un attributo con il valore completed alla cella dati in modo che possa determinare dinamicamente se vogliamo avere l’icona ‘check’ in visualizzazione. Abbiamo originariamente impostato questo valore come false quando abbiamo creato il modulo in orders.service.ts.

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

Inside order-list.component.ts , creare la funzione markCompleted() che usa il data iniettato per passare a una funzione chiamata updateCoffeeOrder() in orders.service.ts.

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

Inside orders.service.ts creare la funzione di gestione. Questa funzione si connetterà e chiamerà il vostro database Firestore in base alla collezione selezionata e all’id del documento. Sappiamo già che la nostra collezione si chiama coffeeOrders e possiamo trovare l’id del documento in base ai parametri passati dalla chiamata della funzione componente.

.set() imposterà il record specifico con qualsiasi dato passato. .set() prende due parametri – i vostri dati e un oggetto settings. Se usate merge: true, allora significa che aggiornate solo la coppia valore-chiave passata piuttosto che sostituire l’intero documento con quello che avete passato.

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

Ora quando cliccate sull’icona ‘check’ nella vostra vista, questa aggiornerà il vostro database e scomparirà perché il vostro attributo è ora impostato a true.

D sta per Delete

Per l’azione finale, imposteremo tutto in modo simile al processo di aggiornamento – ma invece di aggiornare il record, lo cancelleremo.

Imposta un’altra cella dati con un gestore di eventi click che chiama una funzione deleteOrder(). Passeremo l’istanza dei dati order nel ciclo quando l’icona ‘delete_forever’ viene cliccata. Questo ti servirà per l’id del documento. Vedi il codice qui sotto per esempio:

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

Dentro il tuo order-list.component.ts crea la funzione associata che chiama una funzione deleteCoffeeOrder() dentro il tuo orders.service.ts .

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

Dentro il tuo file orders.service.ts, crea la funzione deleteCoffeeOrder() e usa il data iniettato per capire qual è il document id. Come per l’aggiornamento, dovete conoscere sia il nome della collezione che l’id del documento per identificare correttamente quale record volete cancellare. Usa .delete() per dire a Firestore che vuoi cancellare il record.

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

Ora quando clicchi sull’icona ‘delete_forever’, la tua app Angular si attiverà e dirà a Firestore di cancellare il record specifico. Il tuo record scomparirà dalla vista quando il documento specificato verrà cancellato.

Applicazione finale

Puoi trovare il repository Github per l’intero progetto funzionante qui. Dovrete creare il vostro database Firebase e collegarlo voi stessi aggiornando i file di configurazione. Il codice in sé non è perfetto, ma l’ho tenuto molto minimale in modo che possiate vedere come funziona Firestore in un’app Angular senza dover passare attraverso una giungla di codice.

Ho cercato di condensare il tutorial il più possibile senza perdere alcun dettaglio. È stato un mix difficile, ma come potete vedere sopra, molto di esso è principalmente il codice Angular e non molto Firestore. Firebase Firestore può fare query molto più complesse, ma per scopi dimostrativi, l’ho tenuto semplice. In teoria, se la vostra struttura dei dati rimane la stessa, potete sostituire Firestore e mettere un diverso set di connessioni API con il minimo refactoring richiesto.

Parole finali

Personalmente mi piace Firebase per come è facile creare rapidamente progetti pronti per la produzione senza la necessità di creare un intero backend e server per supportarlo. Dal punto di vista dei costi, non è troppo male e i progetti di prova sono gratuiti da avviare (e non ti fanno inserire i dati della tua carta di credito fino a quando non sei pronto a cambiare piano). Nel complesso, ci è voluto più tempo per creare il modulo e l’interfaccia che circonda l’applicazione che l’atto effettivo di collegare l’applicazione a Firestore. Non ho aggiunto la convalida del modulo a questo tutorial a causa della lunghezza, ma creerò un altro post al riguardo in futuro.

Lascia un commento