Come creare una semplice To-do list con Angular 4 e Firebase

Parole Pierdomenico Reitano
Tempo di lettura 40

Angular 4 è forse il framework più utilizzato dagli sviluppatori web e mobile, in questo articolo vedremo come utilizzare l’integrazione con firebase per la creazione di una semplice webapp!

V

Starter Kit

Per portare a termine tutorial ti serviranno pochi semplici tool.

 

Firebase CLI, fondamentale per procedere con il deploy. Puoi installarlo aprendo il terminale e digitando il comando:

> npm install -g firebase-tools

Angular CLI, per eseguire la struttura e l’impostazione del progetto

> npm install -g @angular/cli

Un editor di testo, io utilizzo Visual Studio Code

Impostiamo il nostro progetto Firebase

Prima di tutto vai sulla console di Firebase e crea un nuovo progetto

 

Clicca su Aggiungi Firebase all’applicazione web e copia il contenuto in un file di testo che ti servirà successivamente  

Vai nella sezione Database del menu e seleziona Prova Firestore in versione beta

Successivamente seleziona Avvia in modalità di prova

Nella schermata successiva Seleziona Aggiungi Raccolta

Successivamente aggiungi 2 campi con valori di default

Adesso il database è pronto per interagire con Angular!

Impostiamo il nostro progetto Angular

Prima di tutto genera il tuo progetto usando Angular CLI esegui il comando

> ng new todolist

Una volta completato il setup, spostati nella cartella todolist e installa i pacchetti necessari alla comunicazione con Firebase

> npm install angularfire2 firebase --save

Adesso puoi lanciare il comando che fa partire il browser

> ng serve

Il tuo progetto sarà raggiungibile all’indirizzo http://localhost:4200

Mettiamo le mani sul codice!

A questo punto apri il tuo editor di testo preferito e crea il file firebaseconfig.ts nella cartella /src/app.  i dati che hai salvato durante la fase di configurazione di Firebase.

//inserisci qui i dati che hai salvato in precedenza

export const firebaseConfig = {
 apiKey: '',
 authDomain: '',
 databaseURL: '',
 projectId: '',
 storageBucket: '',
 messagingSenderId: ''
};

Adesso vai a impostare il modulo app.module.ts che si trova nella stessa cartella

// sopra i moduli standard importati da angular
// moduli che occorrono per l'interazione con firebase
import { AngularFireModule } from 'angularfire2';
import { AngularFirestoreModule } from 'angularfire2/firestore';
// Credenziali di accesso a Firebase
import { firebaseConfig} from './firebaseconfig';
@NgModule({
 declarations: [
   AppComponent
 ],
 imports: [
   BrowserModule,
   FormsModule,
   HttpModule,
   AngularFireModule.initializeApp(firebaseConfig),
   AngularFirestoreModule
 ],
 providers: [],
 bootstrap: [AppComponent]
})
export class AppModule { }

Adesso metti le mani sul modulo app.component.ts per verificare se il collegamento al Firebase funziona come dovrebbe.

import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
interface Todos {
 description: string;
 done: boolean;
}
@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
 todosCollection: AngularFirestoreCollection<todos>;
 todos: Observable<todos[]>;
 constructor(private afs: AngularFirestore) { }
 ngOnInit() {
   this.todosCollection = this.afs.collection('todos');
   this.todos = this.todosCollection.valueChanges();
 }
}

Prima di tutto definisci due proprietà:

todosCollection, del tipo Todos (l’interfaccia che abbiamo definito sopra).

todos che contiene l’array che ci viene ritornato.

Nella funzione ngOnInit, eseguita al caricamento del componente, fai un bind di todosCollection all’istanza di AngularFirestore, usando il metodo .collection al quale dovrai passare il nome della raccolta (todos)

Successivamente fai un bind di todos a todosCollection e usa il metodo .valuechanges() che ti ritornerà un “observable”.

Adesso nel modulo app.component.html fai apparire i contenuti presi da Firebase.

<ul>
 <li *ngfor="let todo of todos | async">
   <b>{{todo.description}}</b>
   <em>{{todo.done}}</em>
 </li>
</ul>

Adesso è arrivato il momento di aggiungere i to-do.

Sempre in app.component.html aggiungi il markup del tuo form

<form>
 <input type="text" [(ngmodel)]="description" name="description" placeholder="Cosa devo fare ...">
 <button type="submit" (click)="addTodo()"> Aggiungi Todo</button>
</form>

In app.component.ts , crea la proprietà description, che ti servirà per fare il 2-way data binding al [(ngModel)]

description: string;

all’interno della classe AppComponent aggiungi la funzione addTodo()

addTodo() {
   this.afs.collection('todos').add({
     'description': this.description,
     'done': false
   });
 }

Ovviamente passeremo alla funzione il valore di ngModel, mentre per quanto riguarda il parametro ‘done’ bisognerà passare false di default

Spuntiamo  i nostri to-do

È arrivato il momento di spuntare i to-do. Per fare ciò avremo bisogno di poter selezionare un singolo todo dal database.

Purtroppo, allo stato attuale, utilizzando .valueChanges(), non hai la possibilità di ottenere l’id di ogni singolo to-do, perché è considerato un metadata.

Per ottenere questo risultato bisognerà apportare un po’ di modifiche al nostro codice.

Prima di tutto, esattamente sotto l’interfaccia Todos, ne aggiungiamo una nuova che estende quest’ultima.

interface Todo extends Todos {
 id: string;
}

Successivamente modifica la proprietà todos

todos: Observable<todos[]>;

A questo punto bisogna ridefinire this.todos all’.ngOnInit() per poter usare .snapshotChanges(), che differentemente dal precedente metodo restituisce anche diversi metadata che includono l’id del todo.

this.todos = this.todosCollection.snapshotChanges()
     .map(actions => {
       return actions.map(a => {
         const data = a.payload.doc.data() as Todo;
         const id = a.payload.doc.id;
         return { id, data };
       });
     });

Bisognerà modificare anche il tuo template.

<ul>
 <li *ngfor="let todo of todos | async">
   <i>{{todo.id}}</i>
   <b>{{todo.data.description}}</b>
   <em>{{todo.data.done}}</em>
 </li>
</ul>

Adesso scrivi la funzione che permetterà di aggiornare i todo.

Modifica il tuo template per ottenere il risultato desiderato.

<ul>
 <li *ngfor="let todo of todos | async">
   <input [checked]="todo.data.done" type="checkbox" (change)="updateTodo(todo.id, $event)">
   <b [class.done]="todo.data.done">{{todo.data.description}}</b>
 </li>
</ul>

Aggiungi una checkbox che ti permetterà di segnare un’attività come completata oppure no. Imposta “checked” se il valore di todo.data.done è uguale a true, al change esegui invece la funzione updateTodo(), passando l’id e l’evento scatenato al change. Infine imposta una classe done, se todo.data.done è true.

Nello styles.css inserisci

.done{
 text-decoration: line-through;
}

Nel component invece definisci updateTodo()

updateTodo(id, event) {
   const checkedVal = event.target.checked;
   this.afs.doc('todos/' + id).update({
     'done': checkedVal
   });
 }

Come puoi vedere non facciamo altro che utilizzare il medodo .doc(), che ci permette di selezionare un singolo todo tramite l’id. Fatto questo utilizziamo il metodo .update() per aggiornarlo.

Eliminare un todo

Utilizzeremo più o meno la stessa tecnica adottata prima per impostare la funzionalità di update.

Nel template, all’interno del ciclo for, aggiungi il bottone che permetterà di cancellare i tuoito-do.

<button *ngif="todo.data.done" (click)="removeTodo(todo.id)">×</button>

Mostra il bottone esclusivamente se il to-do è checkato, e ovviamente passiamo alla funzione l’id.

removeTodo(id){
   this.afs.doc('todos/' + id).delete();
 }

Differentemente da prima, utilizzeremo il metodo .delete(), i nostri to-do verranno cancellati dalla lista.

Aggiungiamo un po’ di stile alla nostra app!

Nel template aggiungi un header

<header>
   <h1>...
</h1></header>

e un main

<main>
 <ul>
    ....
 </ul>
</main>

Nel file styles.css aggiungi

body{
 font-family: 'Helvetica Neue', sans-serif;
 background: #ededed;
 margin: 0;
}
header{
 background: #ff6666;
 padding:.5em;
 display: flex;
 align-items: center;
}
header img{
 max-height: 2em;
}
h1{
 font-weight: 100;
 color: white;
 margin: 0 .5em 0 0;
}
main {
   max-width: 800px;
   margin: 0 auto;
   display: block;
   padding: 2em 1em;
}
textarea, input, button { outline: none; }
form{
 display:flex;
 width: 100%;
 align-items: center;
 box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.15);
}
form input{
 flex:1;
}
form button{
 background:#1c1c1c;
}
form button:hover{
 background:#ff6666;
}
ul {
   list-style: none;
   padding: 0;
}
li {
   background: white;
   margin: .5em 0;
   padding: .5em;
   align-items: center;
   display: flex;
   box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.15);
}
li b{
 font-weight: 100;
 font-size: 1.5em;
 margin: 0 .5em;
 flex:1;
 transition: all .3s;
}
button {
   font-weight: 300;
   color: #ff6666;
   border: none;
   border-radius: 0;
   background: white;
   padding: 1em;
   font-size: .8em;
   cursor: pointer;
   transition: all .3s;
   box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.15);
}
button:hover{
    background: #ededed;
}
input[type="text"] {
   background: none;
   border: none;
   background:white;
   font-size: 1.5em;
   padding: .25em;
   font-weight: 100;
   transition: all .3s;
}
input[type="text"]:focus{
 color: #ff6666;
}
.done{
 text-decoration: line-through;
}

Ecco come apparirà la tua app

È tempo di deploy!

Deployare un’app sfruttando l’hosting che ci offre Firebase è molto semplice, bastano pochi semplici passi.

Prima di tutto vai alla sezione Hosting all’interno della nostra console di Firebase e clicca su inizia

Firebase ti suggerisce di installare la sua CLI, se non lo hai fatto in precedenza, installala adesso e clicca su continua.

Nel secondo passaggio ti vengono fornite tutte le istruzioni per poter procedere con il deploy

Quando lanci il comando firebase init, se non conosci molto bene come funzionano le configurazioni di Firebase, Ti consiglio di selezionare solo l’opzione hosting, per evitare di confonderti con tutte le configurazioni che Firebase mette a disposizione.

Et voilà… la tua app sarà online in pochi minuti!

L’intero codice del tutorial è disponibile su github:

https://github.com/lotrekagency/Todolistfirebase

In questo tutorial abbiamo visto quanto sia facile ed intuitivo sviluppare una semplice web app con degli strumenti potentissimi quali Angular e Firebase. Pensa a quanto potrebbe tornare comodo avere una piattaforma che ti permette di gestire il back-end delle tue app in maniera veloce e con una curva di apprendimento estremamente bassa.

Vi aspetto per nuovi fantastici Tutorial!

Pierdomenico Reitano

Senior Fullstack Developer

Ho iniziato ad approcciarmi con il mondo del web non appena finite le scuole superiori, una mia amica mi disse che frequentava una scuola di web design, così senza pensarci troppo mi iscrissi e fu amore a prima ...