Introducción: Angular, AngularMaterial y Firebase

Un buen stack de herramientas para desarrollar plataformas

Lo primero que debemos entender es que, necesitamos implementar una herramienta que nos va ayudar a ser más productivos a la hora de trabajar con Angular, dicha herramienta es Angular Cli y recomiendo instalarla en tu máquina de forma global para acceder a sus funcionalidades.
También debemos instalar Firebase Tools de forma global para acceder a las funcionalidades de firebase.
Es muy útil tener en cuenta la documentación de Angular Material ya que usaremos algunos componentes de la misma. Cuando usamos Angular Material es muy importante tener en cuenta que necesitaremos tres módulos: @angular/material @angular/cdk @angular/animations. Puedes instalarlo vía npm.
Luego de esto podemos crear un proyecto nuevo o en su defecto, pueden descargar el repo que he desarrollado AQUÍ y seguir el tutorial para entender cada módulo. En caso de clonar, instalen las dependencias ejecutando npm install.
Ahora si en cuanto al proyecto: Lo primero que debemos entender es el flow con el cual un proyecto de este tipo trabaja. En nuestro caso a nivel de front implantaremos los módulos de AngularFirestore para interactuar con Firestore como nuestra base de datos. Firestore es NoSQL y firebase nos ofrece su ecosistema para interactuar con él, lo que quiere decir que no tenemos la obligación de desarrollar un RestApi como backend. Existe la posibilidad de usar Firebase Functions que son funciones que ejecutan eventos dentro de firebase, pero eso lo veremos en los siguientes tutoriales.
Lo primero que debemos ver es nuestro archivo app.modules.ts donde vamos a configurar los módulos que vamos a usar de forma global en nuestro proyecto, esto incluye las funcionalidades de Angular Material. También vamos a configurar el acceso a Firebase. Para que puedas tener tus propias credenciales debes crear una cuenta en Firebase, después un proyecto y por último agregar Firestore al proyecto que creaste: Al llegar a este punto vas a encontrar un script con tus propios accesos. Por último debemos tener en cuenta los componentes que nosotros vamos a crear y usar (OrdersComponent, OrdersListComponent, MainMenuComponent, PlatesComponent, PlatesListComponent)
angular1
angular2
Los módulos los podemos crear con el siguiente comando: ng g c ruta/componente es decir: ng g c components/component
Al ejecutar el comando para crear un componente, el mismo va generar 4 archivos por defecto: component.component.css: Para escribir los estilos propios del componente. component.component.html: Para escribir el maquetado del componente. component.component.ts: Para escribir las funcionalidades del componente (es como un controlador) component.component.spec.ts: Para escribir el test del componente.
En nuestro caso queremos crear un componente que se encargue del menú. AngularMaterial nos ofrece un "skeleton" para configurar lo que necesitamos, solo debemos ejecutar: ng c main-menu. Nuestro componente va tener el siguiente html y ts por defecto. El html lo ajustamos a nuestras necesidades:
angular3
Además, cabe destacar que en la linea 25 llamamos al contenido que se refleje en el renderizado, es decir, estamos frente a un "layout"
Luego de ello vamos a configurar nuestro archivo app-routing.module.ts done nuestras rutas van acceder a nuestros componentes.
angular4
En Angular podemos llamar componentes dentro de componentes y pasarle propiedades, en este caso aplicaremos eso para home donde va llamar dentro de su componente a orders pero sin pasarle propiedades.
angular5
Ahora si, vamos a entender el funcionamiento del proyecto en función de los datos: orders se va encargar de dibujar nuestra vista, agregando el titulo, el componente mat-accordion que nos permite dentro de él colocar otros componentes y desplegarlos o no. Dentro del mismo agregamos un formulario donde crearemos la orden y la lista de platos disponibles.
angular6
En la linea 5 pasamos a las propiedades del componente mat-accordion opened and closed unas funcionalidades que van a identificar cuando desplegar el acordión y cuando no. Dicha funcionalidad la aplica panelOpenState que está declarada en el "controlador" del componente.
En la linea 14 vamos a listar los platos disponibles, donde mostraremos su nombre con un checkbox que, al hacer click, podemos agregar o no a un array que va contener la lista de platos que se agregarán a la orden.
En la linea 36 vemos la función createOrder que se dispara cuando el usuario da click al botón Envíar, esto con una pequeña validación que nos asegure que todos los datos necesarios están listos: Ordén, cliente y por lo menos un producto.
Este último punto es bien interesante porque nos encontramos con un comportamiento reactivo, dicho comportamiento se dá en este caso gracias a @angula/forms que permite instanciar los inputs que se van a usar en los formularios, es por ello que en las lineas 14, 23 y 29 se agregan las propiedades [formControl]="inputname" que termina de generar la reactividad.
Muy lindo todo pero, cómo funciona todo esto? veamos ahora nuestro controlador: Aquí llamamos AngularFirestore, Observable de rxjs y FormControl de @angular/forms. También configuramos nuestras interfaces de Plate y Orders. (si, interfaces, recuerden que estamos escribiendo en Typescript). Cuando el sistema crece es bueno crear una carpeta aparte y colocar allí las intefaces que necesitamos, entonces dentro de los controladores solo las llamamos.
angular7
El decorador @Component configura el selector del componente, el template y el archivo css que le pertenece a dicho componente.
Ahora, veamos la clase: Nuestras variables plates y orders deben ser tipo Observables ya que, AngularFirestore ve devolverle Observables (de nuevo, estamos escribiendo en Typescript, el tipado es esctricto y debe definirse correctamente). Tenemos también panelOpenState que maneja la visualización del acordión en el front, platesSelected es el array donde se van almacenar los platos seleccionados para crear la orden y title es el título de la vista.
En nuestro constructor inyectamos AngularFirestore para poder acceder a sus propiedades dentro de la clase y también hacemos un "get" a firestore de las ordenes y los platos disponibles.
Tenemos dos funciones: addProduct(plate) que va agregar al array platesSelected el plato disponible y createOrder(order) que va crear la orden.
angular8
Nota: me falta validar que, cuando un usuario desselecciona un plato se actualice el array de platos seleccionados correctamente, acepto PR =)
Ahora bien, ya teniendo claro nuestro contexto sabemos que nos hace falta algo, cuál es el componente que lista las ordenes? en la linea 43 de orders.component.html verán lo siguiente:
angular9
Aquí estamos llamando al componente app-orders-list y le estamos pasando la lista de ordenes que recibimos. Es decir, app-orders-list vendría siendo un child de orders.
Ahora bien, veamos que se debe hacer en nuestro child componente (app-orders-list) para recibir dichos datos:
angular10
En la linea 10 vemos @Input orders: any[]; esta configuración permite recibir un array de ordenes del componente padre.
También vale la pena destacar que, llamamos a MatTableModule (componente de Angular Material) para listar nuestras ordenes y ngOnChanges que va recibir dichas ordenes y las va pasar a la vista. displayedColumns es un array que guarda los headers de MatTableModule. Estos detalles pueden verlos en la docu de Angular Material.
Para finalizar, podemos ver el html de la lista de componentes:
angular11
El resultado:
angular12
Pueden ver el sistema en producción AQUÍ
Existe otra sección donde manejamos los platos disponibles, pero creo que este post ya está un poco extenso, entonces es mejor que puedan estudiarlo y cualquier duda me pueden comentar.
En lo personal me gusta Angular, creo que es una herramienta muy buena para hacer front y que la decisión de usar esta u otras como React o Vue es tema de equipo, de proyecto, de empresa o de cliente.
Recuerden, pueden clonar el proyecto AQUÍ
Espero que les sirva, saludos.
REFACTOR: Gracias a la recomendación de un amigo he realizado un pequeño refactor en el archivo app.module.ts donde anteriormente colocamos los datos de acceso a firebase, hemos quitado esto y lo agregamos en environment.ts ya que es la forma correcta.
angular13
angular14
#Typescript
#Angular
#AngularMaterial
#Firebase
#Firestore
Comentarios: Pronto!