Crear tablas dinámicas con JavaScript y AGGrid

Crear tablas dinámicas con JavaScript y AGGrid te permitirá mostrar datos estructurados en forma de cuadrículas con filtros y ordenación.

En este artículo te explico cómo implementar esta fantástica librería para crear tablas dinámicas como la del siguiente ejemplo. Haz click en la imágen para abrir el ejemplo en una ventana nueva.

Ejercicio implementando AGGrid. Haz click en la imagen para abrirlo en una ventana nueva
Ejercicio implementando AGGrid. Haz click en la imagen para abrirlo en una ventana nueva

Si no quieres leer la introducción, y prefieres ir directamente a la parte práctica, haz click aquí

Pocos componentes web son tan aparentemente sencillos y a la vez tan necesarios como las tablas HTML.

Mediante una tabla se puede representar datos de todo tipo, de forma clara y organizada para el usuario.

No obstante, muchas veces no basta con solo formatear los datos en filas y columnas.

También es necesario poder manipular el contenido de dichas tablas, ya sea filtrando, ordenando o incluso editando el propio contenido de las celdas.

Por eso, usar una simple etiqueta <table/> no suele ser suficiente, a la hora de representar datos, como por ejemplo los de un documento CSV.

Por ese motivo existen librerías JavaScript como AGGrid, una biblioteca Js capaz de generar tablas de datos completamente dinámicas.

¿Y a qué me refiero por dinámicas?

Pues ni más ni menos que a tablas que obtienen datos en formato JSON, y construyen “grids” complejos de forma automática, en base a estos.

El caso es que, además, una cuadrícula generada mediante AGGrid es totalmente customizable, y provee al usuario de todo tipo de funcionalidades.

Más adelante voy a profundizar en cada una de ellas, pero deja que te liste algunas de las capacidades más interesantes:

  • Posibilidad de reordenar las columnas de las tablas.
  • Filtrar el contenido de las columnas según un criterio personalizado.
  • Ordenar de forma ascendente o descendente.
  • Anidar filas según una jerarquía establecida.
  • Selección de filas individuales y múltiples.

Cómo ves, AGGrid se antoja un recurso muy interesante para el desarrollo de aplicaciones web donde los usuarios trabajan con datos estructurados.

Tablas y grids para ordenar datos con AGGrid
Tablas y grids para ordenar datos con AGGrid

Antes de empezar a estudiar su API es necesario conocer algo importante acerca del uso de esta herramienta.

AGGrid proporciona dos conjuntos de módulos: @ag-grid-community/all-modules y @ag-grid-enterprise/all-modules. 

Estos módulos tienen diferentes propósitos y vienen con diferentes modelos de licencia.

El módulo de la comunidad (@ag-grid-community/all-modules) son gratuitos y de código abierto

Incluyen un conjunto completo de características que son adecuadas para muchas aplicaciones. 

Se pueden utilizar estos módulos sin pagar absolutamente nada, ya que tienen licencia MIT o similar. 

Por otra parte, los módulos para empresas (@ag-grid-enterprise/all-modules) incluyen características y funcionalidades avanzadas, que van más allá de lo que está disponible en los módulos comunitarios. 

Estas funciones suelen estar más orientadas a los negocios o especializadas para determinados casos de uso.

Para utilizar los módulos empresariales, se debe adquirir una licencia comercial de AG-Grid a través de la página oficial de AGGrid.

https://www.ag-grid.com/license-pricing/

Por supuesto, el tutorial que he preparado al final de la publicación, está basado en los módulos de la comunidad.

Considero que estos módulos “open source” cubren más del 80% de los casos de uso que un desarrollador pueda necesitar.

Sin embargo, te animo a que investigues sobre costes y características específicas de los módulos “Enterprise” (marcados con una “e” roja en la documentación).

Crear tablas con JavaScript y AGGrid a través de su API

AGGrid dispone de “wrappers” para React, Angular y Vue, pero como siempre, analizaré la librería sin usar ninguno de estos “frameworks”, eso nos permite entenderla a un nivel más bajo.

Pero no te preocupes, todo lo que aprendas en este post, lo podrás aplicar en tu proyecto, sea cual sea tu “framework” favorito.

Antes de entrar en materia, veamos algunos datos de interés sobre el repositorio de AGGrid.

En el momento de escribir estas líneas, el proyecto en Github está valorado con más de 11.4k estrellas.

Se encuentra completamente al día (su último commit se realizó hace tan solo dos días) y el módulo de NPM se descarga una media de 602.380 veces por semana.

Es sin duda una de las opciones más populares entre desarrolladores, a la hora de escoger un generador de cuadrículas para JavaScript.

Agregar AGGrid a tu proyecto frontend es tan sencillo como ejecutar el comando de instalación mediante NPM:

npm install --save ag-grid-community

El tipo de instalación que te muestro, descarga el “package” entero de toda la librería. 

Eso implica un mayor peso en el “bundle” final, si deseas minimizar al máximo tamaño final, será necesario que instales la libreria mediante módulos.

Pero ojo, si optas por esta vía de instalación, debes asegurarte de instalar e importar todos los módulos necesarios.

Tras verificar que la instalación se ha completado, ya podemos empezar a importar recursos en nuestro script, como por ejemplo la función de creación de grids.

import { createGrid } from 'ag-grid-community';

Por otro lado, también será necesario importar las hojas de estilo que darán coherencia a la cuadrícula. Se trata principalmente de dos archivos

import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-quartz.css";

El archivo “ag-grid.css” define la estructura y disposición básica de los elementos de la tabla.

Ag-theme-quartz.css aplica estilos según el tema predefinido Quartz

Ese tema se ve profesional, y funciona de maravilla, no obstante, si deseas crear tu propio tema personalizado, puedes seguir las instrucciones definidas en la página web.

https://www.ag-grid.com/javascript-data-grid/themes/#creating-your-own-theme

Pasemos a ver como generar la versión más sencilla de un grid con AGGrid.

import { createGrid } from "ag-grid-community";
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-quartz.css";
const gridOptions = {
  rowData: [
    { make: "Tesla", model: "Model Y", price: 64950, electric: true },
    { make: "Ford", model: "F-Series", price: 33850, electric: false },
    { make: "Toyota", model: "Corolla", price: 29600, electric: false },
  ],
  columnDefs: [
    { field: "make" },
    { field: "model" },
    { field: "price" },
    { field: "electric" },
  ],
};
const myGridElement = document.querySelector("#myGrid");
const gridApi = createGrid(myGridElement, gridOptions);

La forma de implementar AGGrid sigue un patrón bastante habitual en muchas librerías JavaScript.

En esta ocasión cargamos la función “createGrid” directamente de la librería “ag-grid-community”.

Esta función admite dos parámetros, el primero es una referencia a un elemento del DOM que actuará como contenedor de la tabla.

El segundo es un objeto JavaScript literal con una serie de claves y valores que definirán la estructura y características del “grid”instanciado.

En el ejemplo anterior vemos como mediante la propiedad “columnDefs” y la propiedad “rowData” alimentamos el contenido de la cuadrícula.

  • Con columnDefs declaramos la cantidad de columnas de la tabla, y la referencia al dato que deben representar.
  • rowData es un array de datos “en bruto” con formato JSON a partir del cual AGGrid construye las filas y las columnas.

Estas son las dos propiedades más importantes del sistema, pero por supuesto existen muchísimas más, veamos algunas de ellas. 

AGGrid organiza las propiedades de configuración en dos grupos: las que afectan al Grid al completo, y las que afectan a nivel de columnas.

Propiedades de configuración general del Grid

  • columnDefs: Por supuesto la más importante, permite definir las columnas de forma genérica.
  • headerHeight: Ideal para definir el alto en píxeles de la cabecera
  • suppressMovableColumns: Por defecto, AGGrid permite al usuario reordenar las columnas a su gusto mediante “drag and drop”, activando esta booleana, puedes eliminar este comportamiento.
  • colResizeDefault: Cadena de texto para definir el comportamiento general del ancho de las columnas.
  • rowDragManaged: Habilita la posibilidad de arrastrar filas. Para que este atributo tenga efecto, es necesario indicar qué filas de qué columnas deben tener la capacidad de “drag”. Lo veremos en las propiedades a nivel de filas.
  • quickFilterText: Mediante este “string” podemos aplicar un primer filtro genérico sobre cualquier texto de la tabla. Más tarde veremos filtros a nivel de columnas, pero esta opción es ideal si necesitas un único campo para filtrar sobre todo el contenido.
  • suppressExcelExport: Como no podía ser de otra forma, AGGrid también ofrece la posibilidad de exportar el contenido de la tabla en otros formatos. No obstante, la exportación en formato Excel pertenece al módulo “enterprise” así que con “suppressExcelExport” podemos evitar que el usuario exporte el grid en formato hoja de Excel.
  • localeText: Mediante un objeto JavaScript compuesto de claves y valores, es posible traducir los textos mostrados en las tablas a distintos idiomas.
  • pagination: Quizá uno de los parámetros más buscados cuando trabajas con muchos datos. Con un simple booleano asignado a la propiedad “pagination”, AGGrid habilitará un sistema de paginado. Una vez habilitado este parámetro se pueden asignar otras opciones como “paginationPageSize”, etc.
  • sortingOrder: Matriz que define el orden en que se produce la clasificación (si la ordenación está habilitada). Los valores pueden ser ‘asc’, ‘desc’ o nulos. Por ejemplo: [‘asc’, ‘desc’].

Como dije, estos son solo algunos de los parámetros más significativos, a continuación te dejo un listado a todas las opciones disponibles.

https://www.ag-grid.com/javascript-data-grid/grid-options/

Propiedades de configuración a nivel de columnas

Las propiedades que aquí te listaré se deben anidar a nivel de objeto dentro del array de “columnDefs”.

De este modo, dichas propiedades sólo tendrán efecto en la columna especificada.

  • field: Como no, el parámetro más relevante. Este “string” indica el campo del objeto de fila del que se obtienen los datos a nivel de celda. Se admiten referencias profundas a un objeto de fila mediante notación de puntos, es decir, ‘dirección.primera línea’.
  • editable: Este booleano permite al usuario editar el contenido de la celda en esa columna específica, por defecto está desactivado.
  • headerName: Si no se especifica esta propiedad, AGGrid usará “field” como nombre de la cabecera, sin embargo, al especificar “headerName” sobreescribimos ese comportamiento, dotando la columna de un nombre personalizado.
  • onCellClicked: Admite una función de “callback” que se ejecutará cuando el usuario haga click sobre la columna.
  • onCellValueChanged: De igual modo, este evento se ejecutará cuando se modifique el contenido de una celda de la columna.
  • suppressMovable: Del mismo modo que hemos visto “suppressMovableColumns”, esta propiedad aplica el mismo comportamiento a nivel de una única columna.
  • pinned: Genial para mantener visible una columna por encima de las demás, admite los valores: boolean | ‘left’ | ‘right’ | null.
  • sortable: Boleano para activar la función de ordenación sobre una determinada columna.
  • width: Si necesitas fijar un ancho concreto sobre una columna, lo puedes hacer seteando un número de píxeles para “width”.
  • cellRenderer: A través de esta opción, el desarrollador tiene la posibilidad de alterar la forma de cómo se renderiza el contenido dentro de una celda. Admite tanto una función de retorno, como una cadena de texto a modo de constante.
  • cellClass: Permite enviar un array de clases CSS para aplicar en cada celda. Idóneo para customizar el acabado estético, sin alterar demasiado el tema base.

Nuevamente, este listado solo muestra una pequeña parte de todo lo que ofrece AGGrid a nivel de columnas.

Puedes consultar la documentación específica en el siguente enlace:

https://www.ag-grid.com/javascript-data-grid/column-properties/

Métodos, propiedades y eventos del grid, columnas y filas

Hasta el momento, solo he repasado las opciones de configuración disponibles en el momento de instanciar un grid nuevo.

Pero como cabe esperar, el objeto “gridApi” creado a través de la función “createGrid”, expone una gran variedad de propiedades, métodos y eventos, imprescindibles para dinamizar la interacción con la tabla.

La forma más rápida de entender a qué me refiero es tratar de actualizar alguno de los parámetros de configuración “a posteriori”.

Esto se puede hacer gracias al método “setGridOptions”.

gridApi.setGridOption("columnDefs", [
  { field: "mission" },
  { field: "company" },
  { field: "successful" },
]);
gridApi.setGridOption("rowData", [
  { mission: "Space explore", company: "NASA", successful: true },
  { mission: "Travel to center of earth", company: "ACME", successful: false },
  {
    mission: "Learn AGGrid via libreriasJS",
    company: "libreriasJS",
    successful: true,
  },
]);

En el ejemplo que te muestro, es posible ver cómo incluso después de generar el grid, se puede alterar sus propiedades programáticamente, por ejemplo, para mostrar datos totalmente nuevos.

De nuevo, existen métodos a distintos niveles de grid, algunos solo están disponibles accediendo primero a una columna específica.

Una forma de obtener la referencia a una columna en concreto es mediante el método getColumn

const column = gridApi.getColumn(columnId);
column.isPrimary; //retorna true o false

El objeto que retornará nos va a permitir llamar a otras funciones que solo tendrán efecto sobre dicha columna. O bien, consultar propiedades específicas de dicha columna.

De igual modo, a través de “getRowNode” obtendremos una referencia a una fila específica de la tabla.

const row = gridApi.getRowNode(rowId);
row.rowTop; //devuelve la posición de la fila en pixeles

Como puedes apreciar, la interfaz de programación de AGGrid ofrece un nivel de control máximo.

Además de métodos y propiedades, como era de esperar, también se pueden “escuchar” eventos sobre cada nivel.

Eventos a nivel de Grid, se pueden asignar en el objeto de configuración siguiendo el patrón onXXXX, por ejemplo (onCutStart).

También se puede asignar la escucha de eventos a niveles más bajos (de columnas, o incluso celdas), aunque la propia documentación oficial indica que en la mayoría de casos ese nivel de control no es necesario.

Crear tablas dinámicas con JavaScript y AGGrid a través de un ejemplo práctico.

Basta de tanta teoría, ha llegado el momento de “ensuciarnos las manos” creando una aplicación que haga uso de AGGrid.

La idea es obtener los datos de un recurso online como una API, y usarlos para “alimentar” una tabla dinámicamente.

Por supuesto, habilitaremos muchas de las capacidades que ofrece AGGrid.

  • Habilitar el sistema de paginación.
  • Fijar la primera columna para que sea siempre visible.
  • Habilitar la capacidad de filtro y ordenación en algunas columnas.
  • Permitir al usuario editar el contenido de algunas celdas directamente dentro de la tabla, haciendo doble click.
  • Ofrecer la opción de exportar los datos en formato CSV.

En el siguiente enlace encontrarás el código fuente de la práctica terminada, no dudes en acudir a él si, algún punto no se entiende debidamente.

https://github.com/Danivalldo/libreriasjs/tree/master/AGGrid

Iniciamos la práctica preparando un “layout” HTML compuesto por los siguientes bloques.

<div class="header">
  <h1>Ejercicio con AGGrid - libreriasjs.com</h1>
</div>

Una sencilla cabecera para contextualizar al usuario.

<div id="myGrid" class="ag-theme-quartz my-grid-container"></div>

Una “div” contenedor, ahí es donde pediremos a AGGrid que levante la tabla dinámica.

<div>
  <button class="download-btn">Convertir a CSV</button>
</div>
<pre id="csv-container"></pre>

También incluiremos un botón, y una área de exportación de datos en formato CSV.

Aunque sea simple, ésta estructura nos servirá para nuestra aplicación.

Seguidamente aplicamos algunos estilos CSS, para hacer un poco más corporativa toda la interfaz.

:root {
  font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 24px;
  font-weight: 400;
  background-color: #f7f7f7;
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-text-size-adjust: 100%;
}
.main-container {
  max-width: 1000px;
  margin: 0 auto;
  .header {
    background-color: #1c67a4;
    padding: 5px 20px;
    box-sizing: border-box;
    font-size: 10px;
    color: #fff;
    border-top-right-radius: 10px;
    border-top-left-radius: 10px;
  }
  .download-btn {
    background-color: #1c67a4;
    border: 1px solid #175587;
    border-radius: 5px;
    padding: 10px 20px;
    font-size: 16px;
    font-weight: 600;
    color: #fff;
    cursor: pointer;
    transition: all 0.3s ease-in-out;
    margin-top: 15px;
    &:hover {
      background-color: #2a6798;
    }
  }
  pre {
    font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
      "Courier New", monospace;
    color: #fff;
    font-size: 14px;
    line-height: 20px;
    font-weight: 400;
    padding: 10px;
    border-radius: 5px;
    max-height: 400px;
    overflow-y: scroll;
    background-color: #313131;
    display: none;
    &.visible {
      display: block;
    }
  }
  .my-grid-container {
    height: 500px;
  }
}

Con esta base lista, ya estamos en disposición de programar el script JS.

Por supuesto antes de empezar será necesario instalar las dependencias.

npm i ag-grid-community

Iniciamos el archivo main.js importando los recursos necesarios, y cargando la hoja de estilos.

import { createGrid } from "ag-grid-community";
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-quartz.css";
import "./style.css";

Guardamos referencias a dos elementos del DOM en distintas variables.

const csvContainer = document.querySelector("#csv-container");
const myGridElement = document.querySelector("#myGrid");

Seteamos un objeto de configuración de la tabla, de momento sin datos, y generamos un nuevo grid vacío, con la función createGrid.

const gridOptions = {
  suppressMovableColumns: false,
  rowSelection: "multiple",
  pagination: true,
  rowData: [],
  columnDefs: [],
};
const gridApi = createGrid(myGridElement, gridOptions);

Presta atención a los parámetros de configuración para activar la selección múltiple, limitar la reordenación de columnas, y activar la paginación.

Añadimos la acción de exportación de datos en CSV, vinculando un evento de click sobre el botón, y llamando al método getDataAsCsv de gridApi.

document.querySelector(".download-btn").addEventListener("click", () => {
  const csvData = gridApi.getDataAsCsv();
  csvContainer.classList.add("visible");
  csvContainer.innerHTML = csvData;
});

Para terminar, ralizamos una llamada asíncrona al recurso «movies.json» del servidor, y seteamos de nuevo las opciones del grid con el método «setGridOption».

Fíjate bien en cómo además, activamos propiedades a nivel de columnas, por ejemplo, fijando la primera columna o habilitando la capacidad de edición del contenido en cada una de ellas.

window.addEventListener("load", async () => {
  const res = await fetch("./movies.json");
  const rowDataMovies = await res.json();
  gridApi.setGridOption("columnDefs", [
    {
      headerName: "Título",
      filter: "agTextColumnFilter",
      pinned: "left",
      field: "title",
      headerCheckboxSelection: true,
      checkboxSelection: true,
      editable: true,
    },
    {
      headerName: "Año",
      filter: "agNumberColumnFilter",
      field: "year",
      editable: true,
    },
    {
      headerName: "Género",
      field: "genre",
      editable: true,
    },
    {
      headerName: "Director",
      field: "director",
      editable: true,
    },
    {
      headerName: "Premios",
      field: "awards",
    },
    {
      headerName: "Actor principal",
      field: "lead_actor",
      editable: true,
    },
  ]);
  gridApi.setGridOption("rowData", rowDataMovies);
});

Material adicional y recursos para seguir aprendiendo

Siempre es bueno conocer nuevas herramientas que nos faciliten el trabajo.

Y AGGrid es sin duda una de estas herramientas, en cierto modo me recuerda a otra librería que ya analicé en su momento.

Crear bloques WYSIWYG con TinyMCE

Al igual que AGGrid, TinyMCE agrega una capa de interacción muy completa a un elemento web tan simple como lo es el textarea.

En fin, espero que esta guía te sirva en tus próximos proyectos, aquí te dejo un listado a varios recursos para seguir aprendiendo.

Hasta la próxima!

2 comentarios en «Crear tablas dinámicas con JavaScript y AGGrid»

Deja un comentario