En este tutorial usaremos Angular y Firebase (con el poderoso Typecript) para implementar una aplicación web en tiempo real “Book Trading”
La solución debe cumplir con las siguientes historias de usuario:
- Puedo ver todos los libros publicados por cada usuario
- Puedo agregar un nuevo libro a mi biblioteca
- Puedo proponer una operación y esperar a que el otro usuario acepte la operación.
Al mismo tiempo, comenzaremos a resolver uno de los desafíos de la certificación de back-end del Free Code Camp 🎉.
Firebase
Firebase es una base de datos en la nube NoSQL en tiempo real (pero también servicio de almacenamiento y mensajería en la nube y servicio de autenticación y, vea aquí ) que lo ayuda a crear aplicaciones sin crear el backend (o permitiéndole agregar a alguien más tarde), vea las funciones ). Puede guardar y recuperar objetos JSON , crear autenticación de usuario y obtener actualizaciones de datos en tiempo real a través de dispositivos conectados en milisegundos : los datos permanecen disponibles si su aplicación se desconecta , proporcionando una excelente experiencia de usuario independientemente de la conectividad de la red.
Configuración de Firebase
config
claves en src/environments/environment.ts
(haga lo mismo para environment-prod.ts
), el resultado debe ser similar a este (tenga en cuenta que estas informaciones siempre estarán disponibles en la Authentication
pestaña y luego haga clic en el Web setup
botón en la parte superior) esquina derecha):
exportar entorno const = { producción : verdadera , base de fuego : { apiKey : ‘xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx’ , authDomain : ‘fcc-book-trading-173021.firebaseapp.com’ , databaseURL : ‘https://fcc-book-trading-173021.firebaseio.com’ , projectId : ‘fcc-book-trading-173021’ , storageBucket : ‘fcc-book-trading-173021.appspot.com’ , messagingSenderId : ‘763399536402’ } } ;
Database
pestaña, luego Rules
y cambie las reglas de esta manera (¡no olvide publicarlas ! Recuerde también restaurarlas cuando agregue la autenticación real 😅){
“reglas”: {
“.read”: “auth == null”,
“.write”: “auth == null”
}
}
Angular
Procedamos creando una nueva solución angular (siempre usando la sorprendente CLI angular)
npm i -g @ angular / cli @ latest // si aún no está instaladong new fcc-book-trading
Soy fanático de los observables y de todas las API que proporcionan una notación fluida: por lo tanto, utilizaremos la biblioteca angular oficial para Firebase, es decir angularfire2
.
cd fcc-book-trading /npm i firebase angularfire2
Usaremos Firebase con la ayuda de los observables: estos nos permitirán tener una interfaz receptiva y aprovechar al máximo las actualizaciones en tiempo real proporcionadas por este maravilloso conjunto de tecnologías.
Aquí hay un ejemplo de un componente simple que muestra una lista de objetos de libros proporcionados en tiempo real por una base de datos de Firebase (cópielos y péguelos en su src/app/app.module.ts
):
importar { Componente } desde ‘@ angular / core’ ;
importar { AngularFireDatabase , FirebaseListObservable } desde ‘angularfire2 / database’ ;
Libro de clase {
constructor ( título público ) { }
}
@ Componente ( {
selector : ‘app-root’ ,
plantilla : `
<ul>
<li * ngFor = “let book of books | async”>
<pre> {{libro | json}} </pre>
</li>
</ul>
“
} )
clase de exportación AppComponent {
libros públicos : FirebaseListObservable < Libro [ ] > ;
constructor ( db : AngularFireDatabase ) {
esta . libros = db . lista ( ‘/ libros’ ) ;
}
}
angularfire2
.src/app/app.module.ts
):
importar { Componente } desde ‘@ angular / core’ ; | |
importar { AngularFireDatabase , FirebaseListObservable } desde ‘angularfire2 / database’ ; | |
Libro de clase { | |
constructor ( título público ) { } | |
} | |
@ Componente ( { | |
selector : ‘app-root’ , | |
plantilla : ` | |
<ul> | |
<li * ngFor = “let book of books | async”> | |
<pre> {{libro | json}} </pre> | |
</li> | |
</ul> | |
“ | |
} ) | |
clase de exportación AppComponent { | |
libros públicos : FirebaseListObservable < Libro [ ] > ; | |
constructor ( db : AngularFireDatabase ) { | |
esta . libros = db . lista ( ‘/ libros’ ) ; | |
} | |
} |
AngularFireModule
y AngularFireDatabaseModule
en tuapp.module.ts
importar { BrowserModule } desde '@ angular / platform-browser' ; importar { NgModule } desde '@ angular / core' ; importar { AngularFireModule } desde 'angularfire2' ; importar { AngularFireDatabaseModule } desde 'angularfire2 / database' ; importar { AppComponent } desde './app.component' ; importar { entorno } desde '../environments/environment' ; @ NgModule ( { declaraciones : [ AppComponent ] , importaciones : [ BrowserModule , AngularFireModule . initializeApp ( entorno . firebase , 'fcc-book-trading' ) , AngularFireDatabaseModule ] , proveedores : [ ] , bootstrap : [ componente de la aplicación ] } ) clase de exportación AppModule { }
ng s
en tu consola.Database
pestaña y luego Data
agregue un libro nodo con algo dentro it).
books
en este caso) como las tablas anticuadas. Aquí estamos hablando de listas de objetos JSON en lugar de tablas , utilizando la función push () para agregar objetos en lugar de filas a nuestra base de datos en tiempo real.books
está poblada por dos objetos que presentan el “cuerpo” de un libro con los campos respectivos. Tenga en cuenta que Firebase es una base de datos NoSQL, por lo que podríamos guardar otros “tipos” de objetos en la misma lista, incluso si no son libros. Como estamos explorando esta tecnología, asumiremos que cada lista contiene solo un “tipo de objeto”, pero es interesante resaltar esta característica (piense en la posibilidad de almacenar datos que cambian de forma con el tiempo, agregando o eliminando campos 🎉).src/app/app.component.ts
)
@ Componente ( { selector : ‘app-root’ , plantilla : ` <! – contenido anterior -> <button (click) = “AddBook ()”> ¡Agregue un libro! </button> “ } ) clase de exportación AppComponent { // contenido anterior bookCounter privado = 0 ; AddBook público ( ) : vacío { let newBook = new Book ( `Mi libro # $ { this . bookCounter ++ } ` ) ; esta . los libros . empujar ( libro nuevo ) ; } }
Consultas de Firebase
@ Componente ( { selector : ‘app-root’ , plantilla : ` <ul> <li * ngFor = “let book of books | async”> <pre> {{libro | json}} </pre> </li> </ul> <button (click) = “addBook ()”> ¡Agregue un libro! </button> <button (click) = “filterBooks ()”> Filtrar libros </button> “ } ) clase de exportación AppComponent { libros públicos : FirebaseListObservable < Libro [ ] > ; bookCounter privado = 0 ; filtro privado = ” ; constructor ( db privado : AngularFireDatabase ) { esta . libros = db . lista ( ‘/ libros’ ) ; } addBook público ( ) : vacío { const newBook = new Book ( `Mi libro # $ { this . bookCounter ++ } ` ) ; esta . los libros . empujar ( libro nuevo ) ; } public filterBooks ( ) : void { esta . libros = esto . db . lista ( ‘/ libros’ , { consulta : { orderByChild : ‘título’ , equalTo : ‘Mi libro # 1’ , } } ) ; } }
orderByChild
operador al especificar que filtre el campo title
para My book #1
: después de invocar la filterBooks
función, obtendremos una nueva instancia de la lista y una actualización de la interfaz (para evitar este comportamiento desagradable y usar todas las funciones proporcionado por Angular correctamente; en mi caso, utilicé la sinergia Pipes & Observables para obtener el resultado, consulte el repositorio aquí y aquí ).¡La buena noticia lamentablemente termina aquí! Si quisiéramos filtrar los libros hechos (en nuestro ejemplo) por ‘John Doe’, descubriríamos uno de los muchos límites de Firebase: la incapacidad de concatenar operadores para realizar consultas complejas 😢. Para alcanzar el objetivo, deberíamos exponer la relación entre autores y libros a otra lista, simplificando (pero en realidad duplicando) la información que se filtrará … pero hay esperanza: ¡consulte Cloud Firestore vs Realtime Database y mi artículo sobre Cloud Firestore 🎉!