Integrar DataTables en Angular

Al igual que cualquier otra librería externa, si queremos usar DataTables en nuestro proyecto Angular debemos integrar el código de DataTables dentro de la estructura de archivos que maneja el CLI.

Por supuesto, eso debemos hacerlo «a la manera de Angular». Básicamente, eso se refiere a dos cosas: por una parte, la forma de integrar DT (nos referiremos así a DataTables en lo sucesivo) en la estructura de archivos, como la forma de usar DT en cada componente donde lo necesitemos.

En este artículo vamos a aprender a integrar DT (eso sólo tendremos que hacerlo una vez en todo el proyecto) y pondremos un sencillo ejemplo de uso, que luego completaremos en el próximo artículo.

INCORPORANDO DT AL PROYECTO

Para poder usar DT en un proyecto Angular, debemos incorporarlo al mismo, de una forma similar a como hacemos con jQuery o Bootstrap. Para ello, en la consola, estando en la raíz de nuestro proyecto (podemos usar la consola de VSC, claro), teclearmos:

npm install jquery

Esto lo teclearemos si aún no hemos incorporado jQuery. Si ya tenemos esta herramienta integrada en nuestro proyecto, omitiremos esta línea. A continuación seguiremos con:

npm install datatables.net
npm install datatables.net-dt
npm install angular-datatables
npm install @types/jquery --save-dev
npm install @types/datatables.net --save-dev

Observa que las dos últimas instalaciones son para desarrollo. No influirán en la versión en producción de nuestra aplicación Angular.

En el archivo angular.json debemos incorporar, tanto los CSS de DT como su JavaScript. Para ello, actuaremos sobre las claves styles y scripts, que ya conocemos. Te muestro el fragmento de este archivo que se ve afectado, teniendo ya instalados jQuery, Bootstrap y alguna cosilla más, para que veas como queda:

INTEGRAR DT A NIVEL DE MÓDULO

Tenemos que referenciar DT en cada módulo en el que haya un componente que vaya a usar esta herramienta. En el ejemplo de nuestro CRUD, vamos a usarla para la lista de socios. Eso es el MembersListComponent. Por lo tanto, el módulo afectado es MembersModule. Debemos retocar members.module.ts, así:

Observa, en las líneas resaltadas (9 y 16), como integramos DT en el módulo. Te insisto. Esto deberemos hacerlo en cada módulo en el que haya uno o más componentes que vayan a hacer uso de DT. En nuestro caso, sólo hay uno, pero en un proyecto de mayor envergadura podrían ser varios los módulos afectados.

Además, tenemos que crear una clase que esté accesible en el ámbito del módulo afectado. Si sólo vamos a usar DT en un módulo, podremos crearla en el directorio classes de dicho módulo. Si vamos a usar DT en varios módulos, lo suyo es crearla a un nivel más global, por ejemplo en el directorio src/app/classes (tendremos que crearlo si no existe), para que sea alcanzable desde cualquier punto de la aplicación.

Esta clase se puede llamar como desees aunque, por buenas prácticas de programación, le daremos un nombre que haga referencia a DT. En este proyecto la hemos llamado DataTablesResponse. La hemos almacenado en un archivo llamado data-tables-response.ts cuyo código es el siguiente:

Como ves, el código es muy simple. Tan sólo define la estructura de datos que manejará DT para «entender» la estructura de la respuesta JSON devuelta por una API y renderizar los datos en la tabla.

DENTRO DEL COMPONENTE

Además de preparar el módulo, en el componente donde vayamos a usar DT también debemos hacer una pequeña preparación. En concreto, deberemos empezar por importar la clase que hemos creado al final del apartado anterior:

import { DataTablesResponse } from '../classes/data-tables-response';

En la declaración de las variables de la clase debemos crear una variable que almacenará, en formato JSON, las opciones de DT para nuestro componente. Como sabes, Cuando usamos DataTables se pueden definir gran cantidad de opciones de presentación, funcionamiento, etc. En Angular estas opciones se almacenan en una variable específica que luego se enlazará desde la vista. A esta variable la hemos llamado dtOptions, y se declara así:

dtOptions: DataTables.Settings = {};

Como ves, ya le estamos indicando que contendrá los ajustes (Settings) de DT para este componente.

A continuación, dentro de la inicialización del componente -el método ngOnInit()– es donde debemos declarar toda la operativa que:

  • Accederá, al inicio del componente, a la API, pidiendo los datos de los miembros.
  • En cada solicitud de ordenación, filtrado, o cambio de número de elementos a visualizar, volverá a acceder a la API, leyendo los registros que cumplan con dicha solicitud.
  • En cada cambio de página de datos en la paginación de la tabla, volverá a enviar otra solicitud, y recuperará los registros adecuados.
  • Dispondrá los datos recuperados en el formato correcto para que puedan ser renderizados correctamente en la vista.

Como ya sabes, el plugin DataTables se basa en continuas peticiones al servidor. Estas van configuradas mediante una serie de opciones. Es la API en el servidor la que recupera los datos que corresponden a la solicitud enviadas y los devuelve en formato JSON. El plugin prepara esos datos para ser renderizados por la vista.

En concreto, las opciones las declaramos así:

Como puedes ver, todas las opciones de la operativa se declaran dentro de la variable dtOptions, que hemos creado anteriormente. Las opciones de funcionamiento, paginación, mensajes etc aparecen en las líneas de la 2 a la 21. Están documentadas en la documentación oficial de DataTables (https://datatables.net) y en el blog eldesvandejose, por lo que no vamos a meternos aquí a detallarlas.

Lo que nos interesa es la forma de comunicar con la API que nos proporcionará los datos necesarios. Esto sí presenta cambios entre usar DT en un proyecto «convencional», o en Angular. En el blog que te he mencionado anteriormente tienes la forma de trabajar estos datos en un proyecto no Angular. Aquí vamos a aprender como leer los datos de la API a la manera de Angular.

Entre las líneas 22 y 44 se define una llamada a través del objeto http, de la clase HttpClient, que está definido en el servicio HttpConnectService, represantado por el objeto connectService. Este lo conocemos bien, porque lo hemos creado nosotros anteriormente. Lo que hacemos es usar el método post para enviar la llamada, que nos deberá devolver un objeto JSON cuya estructura se ceñirá a la definida en la clase DataTablesResponse, que hemos creado en este mismo artículo. Lo ves en la línea 24. En la 25, además, se especifica la URL de la API.

Como ya sabes, lo que vamos a obtener es un observable, por lo que usamos el método subscribe() para obtener los resultados, mediante una función de fat arrow. Los resultados entran en la variable que hemos llamado resp. A partir de ella se recuperan el número de registros totales, el número de registros filtrados (si estamos, por ejemplo, haciendo una búsqueda), y una matriz, llamada data, que contiene los datos que nos devuelve la API de los miembros que vamos a mostrar.

En la línea 30 le añadimos la clase form-control.sm de bootstrap al selector del número de elementos a mostrar, y al campo de búsqueda de datos.

En las líneas 36 a 38 hacemos que si el número de registros filtrados (número de registros que se muestran) es mayor que cero, es decir, si hay registros que mostrar, no aparezca el mensaje de aviso de que no hay registros. Este es un pequeño bug en la versión de DT para Angular, que aún no está solucionado por el fabricante, así que tenemos que controlarlo de este modo,

En la línea 42 se establece el orden de las columnas a mostrar.

LA VISTA DEL COMPONENTE

En la vista del componente debemos crear la estructura básica de una tabla, en la que se alojarán los datos que devuelva la lógica. Esta es la operativa «normal» de DataTables en cualquier proyecto. La diferencia que más destaca cuando usamos Angular es que esta estructura debe estas bindeada a la matriz dtOptions de la lógica, tal como ves en la línea 6. El código es muy simple:

LA API

La API que lee los datos se ejecuta a la carga del componente, y cada vexz que se cambia «algo» (el número de registros a mostrar, la ordenación por una columna, una búsqueda, la paginación, o lo que sea). La API recibe una solicitud, con los datos de la búsqueda. Como va por el método post de la clase HttpClient, se recibe por php://input, en el caso de que nuestra API sea PHP, como las que usamos aquí. Si fuera una API de NodeJS, por ejemplo, la cosa sería de otra manera, pero esto no nos concierne ahora. El caso es que la API recibe los siguientes datos:

El dato draw es un número de orden de solicitud. Desde que carga el componente, se ejecuta la primera solicitud, y cada nueva solicitud se va numerando consecutivamente. Deberemos devolverlo en el JSON de la respuesta.

Luego hay una matriz por cada una de las columnas solicitadas, con una serie de datos inherentes a dicha columna. Como en nuestro ejemplo se solicitan tres columnas (como ves en la línea 96 del listado completo de members-list.component.ts), aquí aparecen tres matrices.

Después, hay unos datos relativos a la ordenación (order), el registro de inicio (start), el número de registros a obtener (length) y el dato a buscar (search). Como esta es la primera carga, estos datos no tienen información relevante, pero pueden tenerla en sucesivas peticiones.

Con todos estos datos, debemos construir tres consultas a ejecutar:

  • La primera, recuperará los datos que cumplan las condiciones de búsqueda (si las hay), ordenados por el criterio establecido (si hay alguno) y con la limitación del número de registros correspondiente.
  • La segunda contará el número de registros que cumplan la condición de búsqueda establecida, sin limitaciones (sin la cláusula LIMIT).
  • La tercera contará el número total de registros de la tabla.

Con toda la información recuperada en las tres consultas se construye una matriz, y se codifica en JSON antes de devolverla a DT.

Si, como supongo, estás familiarizado con PHP, seguir el código de la API no te supondrá ningún problema, ahora que ya sabes los datos que recibe, y los que necesita retornar.

CONCLUYENDO

Ya va siendo hora de cerrar este artículo, que ya se está haciendo muy largo. Hemos hecho un uso muy tosco de DT, pero hemos aprendido mucho (al menos, yo, y espero que tú también). Ni siquiera hemos incluido aún los enlaces de nuevo registro, edición o borrado para los administradores de mayor nivel. Eso lo haremos en el próximo artículo. Sin embargo, hemos sentado los conceptos fundamentales del uso de DT en un componente de Angular. Como siempre, la aplicación, en su estado actual, la tienes lista para descarga en este enlace. Nos vemos en el próximo artículo. Un saludo.

   

Deja un comentario