paso3old - keblato/TutorialesTalleres-Angular GitHub Wiki

Paso 3

Los requerimientos de este nuevo paso son los siguientes:

  1. Ver las críticas de un libro
  2. Paginar la lista de críticas
  3. Paginar la galería de libros

Además de eso, se explicarán ciertos cambios en la interfaz:

  1. Una nueva barra de navegación
  2. Un nuevo footer

Checkout del paso 3

Deberá realizar el checkout tanto del proyecto del front como del back.

Ejecute en cada directorio los comandos:

git fetch

git checkout paso-3

npm install

Cambios en la base de datos

Para este paso, la base de datos ha cambiado. Para modificarla, deberá entrar a MySQL Workbench, conectarse, hacer click derecho en la base BookStore y seleccionar Drop Schema.

Luego, deberá volver a realizar el procedimiento descrito en el paso 2 para crear la base de datos a partir del archivo actualizado bookstore.sql, ubicado en la carpeta assets del proyecto del back.

book3-dropschema
Figura 1: eliminación de la base de datos anterior

Ahora, deberá crear e importar la base de datos que está en el dump en la carpeta assets del back. Para ello, en la barra lateral, haga click en Data Import/Restore.

Seleccione la opción para importar desde un archivo, ubique el dump en la carpeta assets del back y haga click en new junto a la base de datos. Llámela bookstore.

book1c-import1
Figura 2: creación e import de la base de datos

Haga click en start import y espere a que la importación finalice

book1c-import2
Figura 3: importación finalizada

Cierre esa pestaña y haga click en el botón de refrescar en la sección Schemas en la barra lateral. Verá que la base de datos ha sido creada e importada satisfactoriamente.

Luego, ejecute el back con:

npm start

Y el front:

ng serve

En su navegador, diríjase a localhost:4200 y verá los cambios de este paso:

book3-booklist
Figura 4: la lista de libros en el paso 3

Las críticas de un libro

Si hace click en cualquiera de los libros, verá que un nueva directiva se ha agregado a la vista. Ésta corresponde a las críticas del libro.

book3-bookreviewlist
Figura 5: las críticas del libro

El nuevo componente

A través del CLI de Angular, se creó el componente BookReviewList.

Este componente se diferencia de los anteriores en dos aspectos principales:

  1. Implementa OnChanges
  2. Hace uso de un paquete para la paginación

OnChanges

Cada vez que el usuario hace click en uno de los libros de la lista "Otros libros que le podrían interesar", la URL cambia únicamente en el id del libro, pero es el mismo componente BookDetailComponent quien procesa los cambios.

Puesto que la directiva de este nuevo componente de críticas es utilizada (BookReviewListComponent) como parte del HTML del componente BookDetailComponent, es necesario que éste sepa que cuando se produjo un cambio de libro, debe recargar las lista de críticas para ese nuevo libro.

Para ello, se utiliza la funcionalidad OnChanges de @angular/core.

Para utilizarla correctamente, se debe definir que el componente implementa OnChanges y agregar la función ngOnChanges.

book3-onchanges
Figura 6: OnChanges - book-review-list.component.ts

En este caso, la función ngOnChanges indica que se debe reinicializar el componente cada vez que un change: SimpleChange se produce.

La función ngOnInit inicializa la lista de críticas en una lista vacía, define que la página de las críticas es 1 y el número máximo de críticas por página.

book3-oninit
Figura 7: OnInit - book-review-list.component.ts

La paginación

Como puede observar, la lista de críticas está paginada. Esto porque llegará un momento en el que el libro tenga muchas críticas, de modo que no podrán presentarse todas al mismo tiempo.

El paquete que se utiliza para ello es ngx-pagination. Para poder utilizarlo, se debió primero instalar la dependencia por medio del comando npm install ngx-pagination --save, y luego importar el módulo en el AppModule para que todos los otros módulos lo puedan utilizar.

book3-appmodule
Figura 8: el paquete de paginación importado en el módulo principal AppModule

Este define una estructura básica para paginar los elementos en una lista. TypeScript permite mostrar listas utilizando *ngFor, para paginar basta con agregar los parámetros de paginación al *ngFor. Por ejemplo:

*ngFor="let item of collection | paginate: { itemsPerPage: 10, currentPage: p }"

En nuestro caso, podrá observar que en book-review-list.component.html, el *ngFor se definió como:

*ngFor="let review of reviews | paginate: { itemsPerPage: itemsPerPage, currentPage: page }"

book3-bookreviewlisthtml
Figura 9: book-review-list.component.html

El atributo itemsPerPage define cuántas críticas puede haber por página, mientras que page lleva la cuenta de la página actual. Ambos atributos son inicializados en la función ngOnInit.

Puede observar también que para que la paginación funcione, se debe agregar la directiva pagination-controls:

<pagination-controls (pageChange)="page = $event"></pagination-controls>

En ella se define que el cambio de una página dependerá de la variable page.

Nota 1: si a futuro espera que el usuario pueda elegir cuántos items ver en una página, es importante que desde el principio define que itemsPerPage va a depender de una variable, y no un número cerrado como en el ejemplo básico de la documentación de ngx-pagination.

Nota 2: para paginar, los desarrolladores tienen dos opciones:

  1. Paginar del lado del servidor (es decir el back). Esto quiere decir que los datos se envían del back al front por página.
  2. Paginar del lado del cliente (es decir en el front). Esto quiere decir el front recibe como respuesta a una sola petición, todos los datos y se encarga él mismo de definir cuántos muestra.

Cada opción se utiliza de acuerdo con criterios diferentes:

  1. La paginación del lado del servidor generalmente se prefiere cuando la cantidad de datos es muy grande, y es problemático enviarlos todos como respuesta a una sola petición, y que el navegador los guarde en memoria (puede disminuir su velocidad).
  2. La paginación del lado del cliente generalmente se prefiere cuando la cantidad de datos no es muy grande, es posible enviarlos en una sola respuesta y no va a impactar la memoria del navegador. En este caso, la ventaja es que la paginación puede ser más rápida puesto que como los datos ya están en la memoria del navegador, un cambio solo implica cambiar la visualización y se ahorra el tiempo que consume realizar una petición al API REST.

Para este ejemplo, la opción elegida es la segunda (paginación del lado del cliente). Es por eso que en una sola petición se obtienen todas las críticas de un libro, y que se utiliza el atributo itemsPerPage para controlar cuántos se muestran a la vez.

Los cambios en el back

Para obtener las críticas de un libro, el componente BookReviewListComponent tiene la función getReviews():

book3-componentgetreviews
Figura 10: getReviews() - book-review-list.component.ts

Esta función llama a BookService para traer la lista de críticas del libro.

El servicio a su vez, recibe por parámetro el id del libro y se conecta con el API REST para hacer la petición:

book3-bookservices
Figura 11: getReviews(bookId) - book.service.ts

Para ello, en el proyecto del back se agregó una ruta el controlador books.ctrl.js para recibir y tratar la petición:

book3-booksctrl
Figura 12: ruta '/books/:bookId/reviews' - books.ctrl.js - API REST

Y la implementación de la lógica de la petición en el servicio books.srv.js:

book3-booksbacksrv
Figura 13: getReviews - books.srv.js - API REST

La paginación de la galería de libros

Mientras que la solución propuesta por ngx-pagination se adapta a las necesidades para la paginación de las críticas de un libro, se prefirió implementar una paginación diferente para la galería de libros con el fin de hacer la visualización más agradable.

Para ello se modificó el componente compartido BookSidebarComponent.

Como puede observar, al código html del componente se le agregaron dos botones. Uno para avanzar y otro para retroceder.

book3-booklist2
Figura 14: paginación de la galería de libros

Para paginar efectivamente, en el componente se creó una lista adicional que contiene los 5 libros que se presentan al usuario en determinado momento. Esta lista es la que se utiliza en el *ngFor del código html del componente.

El componente ahora incorpora nuevas funciones para la paginación.

book3-paginationbooklist
Figura 15: funciones paginación de la galería - book-sidebar.component.ts

En primer lugar, al inicializarse incluye únicamente máximo los primeros 5 elementos de la lista de libros que recibe en el @Input. Ese máximo está controlado por el atributo maxPerPage que se definió como 5.

Si la lista completa de libros tiene contiene más de 5, el componente activa la visualización del botón avanzar por medio del atributo booleano showRight. Este atributo determina si el botón se muestra o no, pues como puede observar en el código html, el tag del botón incluye un *ngIf:

<a id="next-item-button" (click)="nextBook()" *ngIf="showRight"><i class="fa fa-angle-right fa-4x"></i></a>

Las funciones nextBook() y previousBook() son las que se encargan de actualizar la lista a mostrar, y de agregar/eliminar los libros de los extremos según corresponda. Cada vez que un cambio se produce, se valida si los botones se deben mostrar o no (los casos extremos) en la función hideShowButtons().

OnChanges

Este componente también implementa ahora OnChanges para actualizar la visualización cada vez que se produce un cambio en la lista de libros a mostrar (por ejemplo cuando un usuario selecciona uno de los libros de la lista "Otros libros que le podrían interesar" en el BookDetailComponent).

La función ngOnChanges es simple. Cada vez que hay un cambio, se desactivan los botones para avanzar y retroceder y se llama la función initializeList() para que cree una nueva lista a mostrar, basada en la nueva lista de libros que recibe como @Input.

Los cambios en la interfaz

Como puede observar, la barra de navegación cambió para prepararse a los nuevos requerimientos de los pasos 4 y 5. También se agregó un footer con especificaciones del proyecto.

Ambos cambios se realizaron sobre el archivo app.component.html.

La nueva barra de navegación

La barra de navegación ahora incorpora una imagen que está ubicada en la carpeta assets del proyecto del front. Guarda las tres pestañas de navegación (Books, Authors y Editorials), pero agrega 3 nuevos links del lado derecho.

A su vez, también es responsive:

book3-responsivenavbar1
Figura 16: barra de navegación responsive (barra abierta)
book3-responsivenavbar2
Figura 17: barra de navegación responsive (barra cerrada)

En primer lugar, para que la barra sea responsive (es decir que aparezca el botón con las tres lineas para abrirla o cerrarla), fue necesario agregar al proyecto PopperJs y JQuery. Esto porque son estas librerías quienes se encargan de la animación para abrir o cerrar la barra.

Para ello, se instalaron los paquetes: npm install popper --save y npm install jquery --save, y se agregaron los scripts al archivo angular.json:

book3-angularjsonscripts
Figura 18: actualización de los scripts del angular.json

**Nota: **es importante que los scripts queden en ese orden, es decir que estén escritos primero que el de Bootstrap, o de lo contrario la animación puede no funcionar (es decir que el botón no abriría, ni cerraría la barra de navegación responsive)

Además de la funcionalidad del botón, para que la barra funcione correctamente fue necesario hacer uso de las nuevas clases de Bootstrap 4:

book3-navbar
Figura 19: código de la nueva barra de navegación

En primer lugar, está el código del botón que define el data-target="#navbarSupportedContent" y su funcionalidad como un toggle.

Por su lado, la barra ahora incluye un id id="navbarSupportedContent" para que la acción generada por el botón la identifique y la pueda expandir o cerrar. Para ello también es necesario definirle las clases class="collapse navbar-collapse" para que "colapse" correctamente.

Los items dentro de ella están organizados por medio de las clases flex-row y flex-column. Es por ello que los botones de Log-in y Sign-up se encuentran por encima del botón de Checkout. Para alinearlos a la derecha de la barra se utiliza la clase ml-auto.

El nuevo footer

El footer está escrito de manera básica. Incluye el logo de la universidad, texto y un link.

book3-footer
Figura 20: el código del footer

Adicional a esto, fue necesario definir una clase en el .css para asegurar que el footer esté siempre ubicado al final de la página y no debajo del último componente mostrado.

book3-footernotfixed
Figura 21: footer debajo del último componente presentado
book3-footercss
Figura 22: la clase css para asegurar la ubicación del footer
book3-footerfixed
Figura 23: footer fijo al final de la página
⚠️ **GitHub.com Fallback** ⚠️