Esta es la segunda parte de nuestra guía de Angular, Firebase y Firestore. Puedes leer la primera parte [aquí](https://tesel.mx/angular-firebase-firestore-parte-1-6315/(opens in a new tab)).
La ocasión anterior vimos algunas cosas básicas de angular. Hoy para el platillo principal vamos a conectar nuestra task list a Firebase. Esto nos va a servir para hacer persistentes nuestras notas y aprender a utilizar una de las librearías más útiles de angular, angularfire2
. Aprender a utilizar Firebase también tiene la ventaja de que colocar tu app en Firebase va a ser gratuito a menos que tengas mucho tráfico.
Ingredientes
Solo vamos a agregar dos ingredientes a nuestra preparación anterior:
- Firebase
- Angularfire
^7.0.0
Un topping excelente.
Preparación
(0) Crea un nuevo proyecto y base de datos en Firebase
Si ya tienes una cuenta en Firebase y sabes cómo crear un proyecto y una base de datos de firestore
puedes continuar al siguiente paso, si no, sigue leyendo.
Vamos a comenzar por crear una nueva cuenta de Firebase, para lo cual necesitas una cuenta de Google. Una vez en la consola:
- Da click a Add project.
- Nombra tu proyecto. Yo solo voy a utilziar
Task List
. - Puedes o no activar analytics. Son muy útiles, pero no vamos a hablar de esa parte en este artículo.
Tu consola se debe ver así una vez creado tu proyecto.
- En la parte de Database crea una base de datos de
Cloud Firestore
y seleccionatest mode
esto va a hacer tu base de datos insegura, pero solo vamos a probar. Para la región voy a escogernam5
, toma en cuenta que no podrás cambiar esta región una vez que confirmes.
Antes de lanzar un proyecto a tus usuarios revisa con mucho detenimiento las security rules
- En Project Overview, da click al tercer botón
</>
para agregar firebase a un proyecto web. Después de nombrar tu proyecto firebase te va a dar algo de código de javascript y un objeto que se ve así:
var firebaseConfig = {
apiKey: "sGa7pO5vYZAaIE3kr3Do",
authDomain: "test-project-a0613.firebaseapp.com",
databaseURL: "https://test-project-a0613.firebaseio.com",
projectId: "test-project-a0613",
storageBucket: "test-project-a0613.appspot.com",
messagingSenderId: "237742080605",
appId: "1:237742080605:web:B4A4CpnDletYOJqnndcl"
}
Este objeto esta diseñado para ser público, normalmente lo colocarías dentro del
<body>
de tu webapp, de modo que tus usuarios podrán verlo, copiarlo y usarlo en sus propias webapps siempre. Por eso es importante que cuando lances un proyecto a producción te asegures de que las reglas de tu base de datos son seguras.
Este es lo único que nos importa por el momento, porque es lo único que necesitamos para configurar angularfire
.
Refrigera todos los ingredientes para que adquieran la consistencia adecuada al momento de cocinar.
(1) Creando datos de prueba
De vuelta en Firestore vamos a crear una collection para tener datos hacia los cuales conectarnos.
Con un procesador de alimentos integra todos los ingredientes hasta tener una pasta de consistencia cremosa.
(2) Instalando y configurando angularfire2
Puedes instalar angularfire
con este comando
npm install firebase @angular/fire --save
Una vez instalado necesitarás colocarlo en tu src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularFireModule } from '@angular/fire';
import { environment } from '../environments/environment';
@NgModule({
imports: [
BrowserModule,
AngularFireModule.initializeApp(environment.firebase)
],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule {}
Y el objeto que guardamos antes en /src/environments/environment.ts
export const environment = {
production: false,
firebase: {
apiKey: "sGa7pO5vYZAaIE3kr3Do",
authDomain: "test-project-a0613.firebaseapp.com",
databaseURL: "https://test-project-a0613.firebaseio.com",
projectId: "test-project-a0613",
storageBucket: "test-project-a0613.appspot.com",
messagingSenderId: "237742080605",
appId: "1:237742080605:web:B4A4CpnDletYOJqnndcl"
}
};
Con eso esta lista la configuración de Firebase y podemos empezar a conectar nuestro código con la base de datos.
Hornea la pasta durante 20 minutos hasta que se redusca
(3) Conectando nuestro componente la base de datos
Como notarás los cambios que vamos a hacer a nuestro componente son muy pequeños. En el template solo vamos a agregar algo de funcionalidad y un solo cambio para hacer que funcione. Y en el componente vamos a cambiar los tipos de algunas variables.
src/app/tasklist/tasklist.component.ts
import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';
import { Observable } from 'rxjs';
interface Task {
done: boolean;
task: string;
};
interface TaskId extends Task { id: string; };
@Component({
selector: 'app-tasklist',
templateUrl: './tasklist.component.html',
styleUrls: ['./tasklist.component.sass']
})
export class TasklistComponent implements OnInit {
tasksCollection: AngularFirestoreCollection<Task>;
tasks: Observable<TaskId[]>;
newtask: Task = {done: false, task:''};
constructor(private afs: AngularFirestore) { }
ngOnInit() {
this.tasksCollection = this.afs.collection<Task>('tasks');
this.tasks = this.tasksCollection.valueChanges({idField: 'id'});
}
update(task: TaskId) {
let doc = this.afs.doc<Task>('tasks/' + task.id);
doc.update({ done: task.done, task: task.task });
}
submit() {
this.tasksCollection.add(this.newtask);
this.newtask = {done: false, task:''};
}
}
- Primero importamos
AngularFirestore
,AngularFirestoreCollection
yObservable
que vamos a ver con detenimiento acontinuación. tasksCollection: AngularFirestoreCollection<Task>;
es una collection y es el objeto que vamos a utilizar para conectarnos con Firestore.tasks: Observable<TaskId[]>;
Con esta linea creamos un Observable de tipoTaskId[]
, que es un array dónde todos los elementos son de tipoTaskId
Esta última sintaxis parece compleja pero en el uso es muy cotidiano, si quieres saber más lee sobre Generic Types. En la práctica lo que estamos haciendo es suscribirnos a un evento que va a pasar: "En algún momento tasks va a tener un array de TaskId"
constructor(private afs: AngularFirestore) { }
agrega como service un objeto local llamadoafs
que va ser nuestra interfáz con Firestore. No es necesario configurarlo más ya que toda su configuración esta enapp.module.ts
this.tasksCollection = this.afs.collection<Task>('tasks');
le pide a firestore una referencia hacia toda la collection que esta bajo ‘tasks’ en nuestra base de datosthis.tasks = this.tasksCollection.valueChanges({idField: 'id'});
adquiere todos los valores que estan guardados en nuestra collection junto con sus respectivos id’supdate(task: TaskId)
las lineas que estan en esta función le piden a Firestore una referencia al documento individual, al task que estamos modificando. Y entonces actualiza el documento. Lo hacemos de esta forma{ done: task.done, task: task.task }
porque de otra manera estaríamos agregando el campoid
a nuestro documento y no es necesario. ~Creo que esto se puede hacer de una mejor manera. Si se te ocurre alguna forma por favor deja un comentario.~this.tasksCollection.add(this.newtask);
agrega nuestro nuevo task a la collection
Las modificaciones a src/app/tasklist/tasklist.component.html
son bastante simples.
<ul>
<li *ngFor="let task of tasks | async">
<input type="checkbox" (change)="update(task)" [(ngModel)]="task.done">
<input (change)="update(task)" [(ngModel)]="task.task">
</li>
<li>
<input type="checkbox" disabled>
<input (keyup.enter)="submit()" [(ngModel)]="newtask.task" placeholder="Nuevo task">
</li>
</ul>
let task of tasks | async
agregamosasync
. Esto nos permite esperar a que se resuelva un observable. En otras palabrastasks
va a conectarse al servidor de firebase y esto puede tomar tiempo; si no agregamosasync
el template devolvería un error en la consola.(change)=update(task)
mandamos a llamar la funciónupdate()
cuando el checkbox o la caja de texto de cada task tiene algun cambio. Es importante que sea en el método(change)
porque este se ejecuta cuando terminan los cambios son "un hecho", a diferencia de(click)
o(keyup)
.
Coloca directamente sobre el pay 🥧 que horneamos anteriormente.
Y en realidad eso es todo. Como puedes ver los tasks que crees y modifiques se quedan guardados en tu base de datos y se reflejan instantáneamente en tu base de datos de Firestore. Incluso si cambias un valor en la base de datos se va a reflejar de inmediato en tu app, tal es la magia de los observables.
[followall link=https://github.com/teseltech/angular-jumpstart]
En la siguiente parte de nuestra guía de Angular, Firebase y Firestore vamos a convertir esta Task List en un Custom Element lo cual llega al borde de la brujería sin ser brujería en mi opinión.
Anya es actuaria, nuestra CRO, y ha pasado los últimos años llevando su conocimiento de datos e investigación de operaciones al Software y al Diseño. Está obsesionada con los juegos de mesa, su diseño y sus mecánicas. También colecciona sistemas de juegos de rol que jamás juega. Cree que Nolan’s Batman is overrated y va a pasar horas hablando de eso si se lo permiten.
SCRUM | Design [Sprint] Thinking | Python | Fate Core | PbtA | 35 mm
Anya es actuaria, nuestra CRO, y ha pasado los últimos años llevando su conocimiento de datos e investigación de operaciones al Software y al Diseño. Está obsesionada con los juegos de mesa, su diseño y sus mecánicas. También colecciona sistemas de juegos de rol que jamás juega. Cree que Nolan’s Batman is overrated y va a pasar horas hablando de eso si se lo permiten.
SCRUM | Design [Sprint] Thinking | Python | Fate Core | PbtA | 35 mm