El editor de DataTables (IV). Datos de múltiples tablas.

Facebooktwittergoogle_pluslinkedinmailFacebooktwittergoogle_pluslinkedinmail

En este artículo vamos a realizar un ejercicio realmente muy interesante. Se trata de recopilar tablas que están relacionadas entre sí, incluyendo en los formularios de creación y edición campos de tipo select (los clásicos combos desplegables). Este ejercicio es especialmente laborioso y requiere mucha atención para sacarle todo el valor didáctico que posee. A cambio de este pequeño esfuerzo adicional, nos encontraremos con una forma de uso muy habitual en situaciones reales de desarrollo. Veremos que, a pesar de lo aparentemente extenso del código, siempre es más compacto y optimizado (es decir, más robusto, seguro y eficiente) que si programásemos a mano los formularios. Además, es más rápido y fácil de programar.

Al tratarse de un ejercicio basado en un desarrollo real, seguramente los códigos que te ofrezco en este artículo te resulten útiles en tu trabajo, con pocas adaptaciones. Venga, vamos al lío.

EL ESCENARIO

Para este desarrollo hemos empleado, una vez más, una tabla de personal de una compañía, con los datos extraidos de los ejemplos de la propia página de DataTables (https://datatables.net/). El modelado de datos responde a un esquema que ya hemos empleado anteriormente, en otros artículos. Tenemos tres tablas:

  • La de personal.
  • La de ciudades.
  • La de cargos.

Las tablas de ciudades y cargos están relacionadas con la de personal, de modo que, cada elemento de la tabla personal estará relacionado con un elemento de la tabla ciudades y con uno de la tabla cargos, a través del id de cada uno de estos elementos. El id de la ciudad, por tanto, es clave primaria en la tabla ciudades y clave foránea en la tabla personal. Otro tanto ocurre con el id del cargo. Una vez más, para facilitarte las cosas, te dejo la base de datos en este enlace, para que la descargues y te la importes con PHPMyAdmin (o tu herramienta favorita).

Lo que pretendemos en este ejercicio es que, cuando vamos a editar un registro, la ciudad y el cargo de la persona cuya ficha estamos editando aparezcan en sendos combos desplegables, mostrando todas las opciones de las respectivas tablas. Por defecto, en cada combo estará seleccionada la opción correspondiente al valor actual del registro. Cuando vayamos a crear un campo nuevo, podremos elegir cualquier opción. Por defecto, nos aparecerá seleccionada la primera de cada lista. De este modo, limitamos un poco la operativa al usuario, forzándole a que siempre haya un valor seleccionado en los combos.

Cabe añadir que, en este ejercicio, no empleamos combos de selección múltiple (eso lo dejaremos para un artículo posterior). La razón de ello es doble: por una parte, el escenario que hemos dibujado no lo requiere. Por otro lado, para este artículo, bastante tenemos con esto, creeme.

EL SCRIPT PRIMARIO

Vamos a empezar por ver el funcionamiento del script primario, ya que nos aportará interesantes conocimientos sobre el uso de combos en los formularios. Se llama articulo_editor_04.php, y su listado es el siguiente:

El código nos es, en su mayoría, familiar. Las partes más interesantes están profusamente comentadas, para que no te cueste esfuerzo interpretarlo. A pesar de ello, lo verás más claro globalmente cuando hablemos de los scripts secundarios, que también presentan novedades que debemos conocer.

LOS CAMPOS DE TIPO select

Antes de entrar en harina con los scripts secundarios y sus novedades, vamos a conocer algunos detalles importantes sobre la forma en que se crean y emplean los campos de tipo select en un objeto editor.

A la hora de definir un campo de tipo select, debemos, cómo se menciona en el código, establecer las opciones (options). Nosotros no lo hemos hecho en este código (las cargamos posteriormente) debido a que estas pueden variar, y queremos tener la lista actualizada. Si fueran fijas, las definiríamos en el propio campo, como vemos a continuación:

Cómo ves, las opciones se definen como objetos formados por un label (lo que el usuario ve escrito en la lista) y un value (el valor que tiene cada opción para pasarlo con el campo, cuando el formulario sea enviado).

La propiedad def establece cual será el valor seleccionado por defecto, cuando se quiere crear un registro nuevo.

Si la lista de opciones no viene con las claves label y value, sino con otras distintas (por ejemplo, por proceder de un JSON que emplea otras claves), contamos con la propiedad optionsPair, que nos permite indicar cual es el label y cual el value. Observa el siguiente ejemplo.

Aunque menos relevante, también está bien saber que hay otros modos de definir las options de un select. Así mismo, tenemos algunas posibilidades secundarias, como establecer un placeholder. Si no te asusta un poco de inglés, echa un vistazo a https://editor.datatables.net/reference/field/select. No obstante, las opciones más necesarias en el día a día las iremos desvelando en estos artículos.

Hay una opción que, en muchos casos, es imprescindible: se trata de multiple, para crear combos múltiples. Como ya hemos dicho, de esta hablaremos en un artículo posterior, para no meter un exceso de materia en este.

OBTENER EL DATASET

Bien. Aquí vamos a ver uno de los scripts secundarios. Se trata del que recupera el dataset para el objeto DataTables. Esta es una tecnología con la que ya estamos familiarizados de los artículos de DataTables pero, en este caso, hay algunos detalles un poco diferentes, que me gustaría comentar contigo. El script se llama datos_externos_editor_04.php y responde al siguiente listado:

Veamos los puntos de interés. Empieza por fijarte en el primer bloque resaltado, entre las líneas 28 y 38. Lo que hacemos es definir las columnas que leeremos de las tablas, respetando el orden en que se definen en la tabla HTML en el script principal. Colocamos al final aquellas columnas que vamos a necesitar leer pero que no aparecen en la tabla HTML. Esto es importante porque, si no lo hacemos así, al hacer ordenaciones no se harán de la forma correcta.

Fíjate, también, en la línea 128. Cuando leemos el dataset, no vamos a enviarlo tal cual. Esto se debe a que debemos preparar el JSON con los datos colocados según la tabla a la que pertenecen (en seguida veremos el JSON de respuesta, para que entiendas esto). Por esta razón, el dataset lo leemos en una matriz provisional.

En las líneas de la 135 a la 157 preprocesamos el dataset previo que hemos leido, para obtener el dataset definitivo que convertiremos en el JSON final.

El JSON que se devuelve tiene, cómo es lógico, una estructura algo más compleja que cuando leíamos una sola tabla, así:

Cómo ves, cada elemento de data tiene los datos de las tres tablas. Y observa, y esto es MUY importante, que en la parte que corresponde a los datos propios de la tabla personal lo que se ha almacenado bajo la clave ciudad es el id de la ciudad, que es lo que ha salido de la tabla personal. Lo que se ha almacenado bajo la clave cargo es el id del cargo, que es lo que hemos obtenido de la tabla personal. Y estos nombres (personal.ciudad y personal.cargo) coinciden con los correspondientes atributos name de los campos select en la definición del objeto editor del script principal. Si no hubiera esa coincidencia de nombres, los campos select no podrían identificar el valor de la ciudad o el cargo leidos, y no funcionarían.

Fijate que, en cada elemento de data tenemos dos campos con la clave ciudad: uno englobado en personal y otro en ciudades. Con los cargos ocurre otro tanto. En este sentido, los nombres de las tablas están actuando como un espacio de nombres para poder distinguir el campo que contiene el id de la ciudad o el cargo del que contiene su nombre real.

Sé que todo esto suena un poco rebuscado al principio. Sin embargo, si lo piensas, tiene toda la lógica del mundo. Observa la matriz del dataset que ha dado lugar al elemento data del JSON:

Te he puesto la matriz que se genera para que puedas compararla con el JSON. A mi me facilitó la comprensión de esto en su momento y espero que a ti también te sirva de ayuda es estos primeros pasos con el editor.

LEYENDO LAS LISTAS

Si volvemos al script principal, vemos que usamos, cómo hemos dicho anteriormente, el evento preOpen de los formularios del objeto editor para obtener, en tiempo real, las listas de ciudades y de cargos, para los campos select. Esto lo hacemos por si, por ejemplo, mientras un usuario trabaja con esta página, otro usuario añade una nueva ciudad a la lista. Así, cada vez que pulsemos el botón de edición, la nueva ciudad estará inmediatamente disponible.

En realidad, lo que hacemos es leer por ajax la lista de ciudades y de cargos. Aquí vemos el script leer_ciudades_editor_04.php:

Y, a continuación, su contraparte para los cargos, llamado leer_cargos_editor_04.php:

Como ves, no tienen nada de particular. Solo recuperan las listas de ciudades y cargos y las devuelven en JSON, que es como se intercambian siempre datos en DataTables (y en cualquier API que se precie).

PROCESAR LOS FORMULARIOS

Cuando se ha pedido la edición o el borrado de uno o más registros, o la creación de uno nuevo, es necesario, al pulsar el botón de envío del formulario, que se procese este adecuadamente. Esto ya aprendimos a hacerlo en el artículo anterior. Sin embargo, nos encontramos con lo mismo que hemos tenido presente en todo este artículo: al trabajar simultáneamente con más de una tabla, este proceso también resulta modificado. El listado se llama crud_editor_04.php:

Presta especial atención a las líneas resaltadas, y observa la diferencia con las equivalentes del artículo anterior. Cuando nos referimos a los elementos de $datosDeLlamada (es decir, los que han sido pasados por post), hemos añadido el índice ["personal"]. Esto es necesario ya que ahora un campo no se llama, por ejemplo, nombre, sino personal.nombre. Al actuar el nombre de la tabla como espacio de nombres, tal cómo te comenté más arriba, al generar la matriz este espacio de nombres forma una agrupación indexada que debemos referenciar.

LA CONEXIÓN A BD

Seguro que ya te has fijado, pero te lo digo igualmente. Dado que la conexión a base de datos ya no se hace, como veníamos haciendo hasta ahora, en uno o en dos scripts, sino que, en este ejercicio se hace en cuatro, lo que hemos hecho es crearla en un único archivo externo y llamarla dónde hace falta. A partir de ahora, usaremos este sistema, más cómodo y mantenible. El script, conexion_bd_editor.php, no puede ser más simple.

Si la conexión a bases de datos por PDO te ofrece dudas consulta este artículo.

Y, cómo tampoco es cuestión de que andes copiando y pegando todos los códigos, si has llegado leyendo hasta aquí, tienes premio. Te los puedes descargar todos en este enlace. De nada. 😉

     

Un comentario:

  1. Hola,
    Estoy intentando añadir una funcionalidad a una datatable, que consiste en un buscador por columna independiente.
    A partir del ejemplo:
    https://datatables.net/examples/api/multi_filter.html
    he añadido los imput correspondientes, pero el problema está en la función
    $( ‘input’, this. header() ).on( ‘keyup change’, function () {
    if ( that.search() !== this.value ) {
    that
    .search( this.value )
    .draw();
    }
    } );

    Al llenar cualquiera de las cajas de texto para hacer una búsqueda, se genera el error.
    Con la herramienta de desarrollo web de Firefox: red, he comprobado que el error consiste en que, al escribir un carácter en la caja de texto, añade ese carácter al nombre de la columna y lógicamente no encuentra la columna.
    Ej: escribo tx en la columna: ‘tb_asignatura.asignatura
    Fatal error: Uncaught exception ‘PDOException’ with message ‘SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘tb_asignatura.asignaturatx
    Agradecería mucho cualquier sugerencia para solucionarlo.
    Un saludo

Deja un comentario

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