El plugin DataTables (XII). Datos dependientes.

Facebooktwittergoogle_pluslinkedinmailFacebooktwittergoogle_pluslinkedinmail

datatablesExisten desarrollos de proyectos en los que la cosa no es tan simple como crear un tabla con datos. El usuario necesita ver, simultáneamente en la página, dos o más tablas, con datos de diferentes fuentes. Incluso es posible que, por ejemplo, los datos mostrados en la segunda tabla, dependan de un dato seleccionado de la primera tabla, de tal modo que, si hacemos click en un dato de la primera tabla, cambien dinámicamente los resultados que se muestran en la segunda.

Esto, además, tiene un problema añadido. El monitor del ordenador (y la ventana del navegador) no es infinito, ni se estira como chicle. Hay que acotar el espacio, dentro de la ventana de navegación, que reservaremos a cada una de las tablas.

En este artículo aprenderemos a resolver ambas situaciones, de un modo eficiente y elegante, que haga que el usuario tenga “a mano” los datos que necesite y se sienta cómodo trabajando con nuestra aplicación.

EL ESCENARIO

Vamos a partir de una base de datos distinta de la que hemos usado hasta ahora aunque, por convencionalismo, la hemos llamado tambien datatables. Esta vez tenemos una sola tabla, llamada categorias, donde hemos almacenado las categorías de artículos que tiene un distribuidor de electrodomésticos. En las categorías hemos incluido los siguientes datos:

  • id. El id de la categoría. Es un campo numérico autoincrementable que vamos a emplear cómo clave primaria, y también, como veremos enseguida, para relacionar unas categorías con otras.
  • categoria. Contiene el nombre de cada categoría.
  • descripcion. Es un campo de texto “libre”, donde añadiremos la descripción de la categoría, comentarios, etc.
  • depende_de. Es un campo numérico destinado a indicar qué categorías dependen jerarquicamente de cuales. Las categorías principales (las más amplias) tienen en este campo el valor 0, indicando así que no dependen de ninguna. Las categorías que podríamos considerar subcategorías, o categorías secundarias, tienen en este campo el id de la categoría principal de la que dependen. Por eso decíamos que el campo id no sólo sirve de clave, sino también para poder relacionear unas categorías con otras.

La tabla completa, con estructura y unos datos de prueba, te la pongo para descargar aquí, para facilitarte el seguimiento de este artículo. Además de importartela con phpMyAdmin (o la herramienta que emplees al efecto), échale un vistazo a la estructura, para que estés familiarizado con el modelado de datos con el vamos a trabajar.

Lo que queremos es ver una tabla a la izquierda de la página, con las categorías que podríamos llamar “primarias”. A la derecha de cada una hay una flecha y, al pulsarla, en una tabla a la derecha de la página se muestran las categorías dependientes de la primaria que hemos seleccionado. A continuación ves una muestra de como quedaría el resultado final.

dos_tablasCómo ves, cada categoría, tanto de las primarias como de las dependientes, tiene un icono para desplegar comentarios, cómo aprendimos a hacerlo en el artículo anterior.

EL SCRIPT PRIMARIO

En este ejemplo el script primario ya tiene más funcionalidades, y más código. No te asustes. Analizaremos las novedades detalladamente y verás lo fácil que es, a pesar de su aparente complejidad a primera vista. El listado se llama articulo_12.php, y es el siguiente:

Lo primero que nos llama la atención es que, efectivamente, hemos definido dos tablas HTML, entre las líneas 19 y 53. La primera será la que alamacene las categorías primarias (las que en el campo rango tengan el valor P, que son las que en el campo depende_de tienen el valor 0. La segunda tabla está destinada a las categorias dependientes de la que seleccionemos en cada momento en la primera tabla. Observa que, en la primera tabla, hemos definido, en la cabecera, dos celdas sin contenido. La primera ya nos es familiar: encabezará las columnas con los iconos + para ver detalles de la categoría. La última celda vacía encabezará una columnas con unos iconos destinados a ver las categorías dependientes.

En la segunda tabla HTML (la que mostrará las categorías dependeientes) nos llama la atención que la celda con el rótulo ELIGE UNA CATEGORÍA tiene un atributo id. Esto es porque luego cambiaremos dinámicamente el contenido de esa cabecera, haciendo aparecer, en su lugar, el nombre de la categoría primaria elegida.

Lo siguiente que vemos, a grosso modo (en seguida entraremos en detalles) es que hay dos objetos DataTables definidos (líneas de la 62 a la 168). Es lógico, puesto que vamos a trabajar con dos tablas y dos datasets diferentes. A continuación comentamos las novedades que hay en cada uno de ellos (algunas son comunes a ambos, y otras no).

Hemos definido tres opciones nuevas, en ambos objetos DataTables:

"scrollY":                   "340px",
"scrollCollapse":            true,
"paging":                    false,

El primero define la altura máxima que tendrá la tabla (opción scrollY). Si los contenidos exceden de dicha altura, se mostrará una barra de scroll vertical, pero la tabla no excederá de la altura especificada.

La segunda opción (scrollCollapse) hace que la tabla tenga menos altura, si no hay contenidos suficientes, evitando que las filas se sobredimensionen en altura.

Por último, la opción paging, con el valor false, evita que se paginen los resultados del dataset. Así, haya los que haya, se incluirán todos en la tabla. En este caso, nos podríamos haber ahorrado la declaración de las opciones lengthMenu y de iDisplayLength, ya que no las vamos a usar, al no haber paginación de resultados. Simplemente, no las hemos quitado porque “no piden pan” y las tenemos en la platilla de otros ejercicios.

Quiero llamar tu atención acerca de la opción sAjaxSource. Como ya sabes, la usamos para establecer el nombre del script secundario que nos devolverá, por ajax, el JSON con los resultados del dataset. En este caso hacemos uso de una opción poco conocida entre los usuarios de este plugin (y no documentada en la web del mismo, aunque funciona perfectamente). Se trata del hecho de que al nombre del script secundario le podemos añadir parámetros, que serán pasados por GET, con las opciones estándar del plugin, y podrán ser interpretados y usados por el script secundario. Esta es una facultad que, en este caso, nos resulta extremadamente útil. Le pasamos el rango de categorías que queremos ver, y el script secundario actuará en consecuencia (ya veremos cómo). De otro modo, tendríamos que tener dos scripts secundarios, unos para la tabla de las categorías primarias y otro para la de las dependientes. Vemos cómo hacemos uso de esta posibilidad, en la línea 91 para el objeto de las categorías primarias, y en la 144 para el de las dependientes:

"sAjaxSource":                "datos_externos_12.php?rango=P",

"sAjaxSource":                "datos_externos_12.php?rango=D",

Dentro de la definición del objeto DataTables correspondiente a las categorías primarias vamos a fijarnos en la forma en que se declaran las columnas de datos, entre las líneas 97 y 112:

Vemos que hay dos columnas que se han definido (la primera y la última) como no de datos ("data":null). Con la primera ya estamos familiarizados del artículo anterior. Será la que contenga el icono para desplegar y replegar las descripciones de la categoría que aparezca en cada fila. La última es similar, pero contendrá el icono para seleccionar, en la tabla derecha, las categorías dependientes de cada una de las principales de la tabla izquierda. Ambas columnas están declaradas como no ordenables y a cada una le hemos atribuido un nombre de clase diferente (opción className), para poder referenciarlas luego desde jQuery.

Además, observa que a las columnas de datos les hemos atribuido los índices 1 y 2, en lugar de 0 y 1. Esto es porque los datos que tienen que aparecer en esas columnas (nombre de la categoría y estado) tendrán esos índices en el dataset, como comprobaremos cuando veamos el script secundario.

Al definir el objeto DataTables de la tabla de categorías dependientes, también hay algo que nos llama la atención en la definición de las columnas. Observa el fragmento contenido entre las líneas 160 y 162:

La opción columDefs se emplea para referenciar una columna del dataset que no aparece físicamente definida en la tabla HTML. En este caso, estamos referenciando la columna con índice 3. Cuando veamos el script secundario, veremos que esta se refiere al campo depende_de. Este no está definido en la tabla HTML, y no tiene un sitio, digamoslo así, físico. Sin embargo, vamos a necesitar referenciarlo a través del objeto DataTables. La opción columnDefs nos proporciona esta solución. Dentro de poco, en este mismo artículo, veremos para que usamos esta definición y lo entenderás claramente.

Otro punto que nos llama la atención, en el objeto DataTables de la tabla de categorías dependientes está entre las líneas 164 y 169:

La opción searchCols se emplea para que la tabla, a la carga inicial (al cargar la página) busque determinadas condiciones. En este caso, la condición de búsqueda (search) se refiere al primer índice del dataset. Cuando veamos el script secundario, comprobaremos que este primer índice corresponde al dato id. Con esto le estamos diciendo que busque registros cuyo id tenga el valor 0. Como el id es un autoicrementable de MySQL y nunca va a tener el valor 0 (empieza por 1), de inicio obtendremos un dataset vacío para las categorías dependientes, que es lo que queremos, ya que no deseamos que nos aparezcan categorías dependientes hasta que no hayamos elegido una categoría principal.

Las demás filas, que ponen null se refieren a campos del dataset sobre los que no vamos a hacer búsqueda inicial. En este caso podríamos haberlos omitido, ya que la búsqueda inicial la vamos a hacer sobre el primer campo del dataset. Si fuéramos a hacerla, por ejemplo, sobre los campos id y descripcion, que en el script secundario ocupan los índices 0 y 5, respectivamente, podríamos haber hecho algo similar a lo siguiente:

Entre las líneas 174 y 188 vemos un jQuery que se ocupa de seleccionar las categorías dependientes adecuadas cuando pulsamos sobre uno de los iconos de flecha de la última columna en la tabla de categorías primarias:

Lo que vemos es que, cuando se pulsa sobre la celda que tiene la clase celda_de_ver_subcategorias de la sección tbody de la tabla_de_categorias se desencadena un proceso que lanza una búsqueda de un dataset sobre el objeto objetoDataTables_catsDependientes, empleando el método search(), nativo de DataTables. Veamos cómo. en primer lugar, se busca cualquier valor (LIKE '%') en la columna 0, que es la que tiene corresponde con el campo id del dataset. Esto hace que se anule cualquier búsqueda anterior que hubiera sobre ese campo. También se busca el id de la categoría primaria sobre la que se ha pulsado (" = '" + identificadorDeCategoriaPrimaria + "'") en la columna de índice 3, que es la que tiene el valor depende_de en el dataset, cómo veremos en el script secundario. Por último, una vez establecidas estas búsquedas, el método draw(), que ya conocemos del artículo anterior, obtiene el dataset y redibuja la tabla de categorías dependientes.

Entre las líneas 190 y 226 se definen las funciones que despliegan o repliegan los comentarios de las cattegorías primarias y dependientes, cuando se pulsan los correspondientes iconos. El funcionamiento de estos códigos lo vimos en el artículo anterior, con la única salvedad de que ahora tenemos funciones para trabajar con dos objetos DataTables en lugar de con uno sólo.

EL SCRIPT SECUNDARIO

El script secundario lo hemos llamado datos_externos_12.php y su listado es el siguiente:

En primer lugar, fíjate en las líneas entre la 24 y la 31, donde aparecen definidas las columnas de la tabla MySQL que se leen, en el orden que se leen. Ahora puedes comprobar lo que te comentaba, según veíamos la operativa del script primario, respecto al índice que tienen los distintos campos.

Observa la línea 57:

$reglasDeBusquedaPorProgramacion[] = $columnasParaRetorno[4]." = '".$datosDeLlamada['rango']."'";

Cómo ves, aquí hacemos uso del parámetro que pasamos en la llamada, al definir los objetos DataTables, en las líneas 91 y 144 del script primario.

Algo que ya sabemos hacer es manipular los datos del dataset antes de que sean devueltos al script primario. En este caso tenemos que actuar sobre el campo activa (que usaríamos para indicar si la categoría sigue en uso o no). Los valores que almacena la base de datos son S o N (es un campo de tipo enum). Sin embargo, queremos que el usuario vea, en la tabla, los valores o NO. Lo hacemos muy fácilmente con las líneas de la 126 a la 128:

foreach ($DataSet as $keyDL=>$DL){
    $DataSet[$keyDL]["activa"] = ($DL["activa"] == "S")?"SÍ":"NO";
}

Y ya está. Ahora sólo es cuestión de que pruebes el código, y lo sigas para comprobar cada punto que hemos detallado. Te puedes descargar los scripts y la base de datos en este enlace.

     

2 comentarios:

  1. Pingback: El editor de DataTables (II) – El desván de Jose

  2. Pingback: El plugin DataTables (XIV). Más tipos de datos desplegables. – El desván de Jose

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *