Hasta ahora hemos visto algunos ejemplos de uso del editor con algunos tipos de campos, como son los de tipo
text
(que es el tipo por defecto), los combos de tipo select
y los campos de fechas (tipo date
). En este artículo aprenderemos a manejar tres campos nuevos: los de tipo radio
, los checkbox
y las textareas
.
Este artículo es una introducción a dichos campos. En artículos posteriores iremos profundizando, para no sobrecargar una sóla sesión de aprendizaje. Que lo disfrutes.
EL ESCENARIO
Para este ejercicio vamos a partir de una base de datos muy sencilla, ya que esta vez no se trata de trabajar con relaciones entre tablas, sino de ver el funcionamiento de distintos tipos de campos. De este modo, podremos centrarnos en la cuestión de este ejercicio, apartando otros aspectos que pudieran distraernos. La base de datos se llama datatables_casillas
, y contiene, sólo, una tabla llamada usuarios
. Esta tabla representa a los usuarios de un portal donde, por ejemplo, mediante la tenencia de cierto número de créditos, se puede tener acceso a ciertas funcionalidades. Podría ser una red social, o un portal de compras, o de acceso a juegos o películas, etc. Los campos de la tabla son los siguientes:
id
. Cómo de costumbre, empleamos un campo numérico autoincrementable, a modo de clave subrogada, para seguir con las buenas costumbres. En un artículo anterior ya te he comentado las bondades de usar siempre este tipo de campos.nombre
. Contendrá el nombre de pila del usuario.apellidos
. Contendrá el apellido o los apellidos del usuario.genero
. Es un campo de tipo enum, con los posibles valoresM
oF
(de Masculino o Femenino). El valor de este campo se establecerá, en el formulario del editor, mediante el uso de dos botones de radio.es_administrador
. Este es un campo de tipo enum, con los posibles valoresS
oN
(Sí o No), reflejando si el usuario tiene la prerrogativa de ser un administrador del sitio. Este campo lo gestionaremos, en el formulario del editor, mediante una casilla checkbox.creditos
. Es un campo de tipo numérico que refleja el número de créditos que tiene el usuario disponibles para realizar operaciones en un hipotético contexto de consumo de funcionalidades y/o contenidos. Este dato se manejará en el formulario como un campo de tipotext
, al que se le limitará el contenido a datos numéricos, ya que el editor de datatables no posee un campo específico de tiponumber
. El criterio que seguiremos para el funcionamiento es que, si el valor es-1
se considerará que el usuario tiene créditos ilimitados. Este podría ser, por ejemplo, el caso de los administradores (o de algunos de ellos).fecha_alta
. Un campo de tipo date, que contendrá la fecha en que se registra el usuario en el portal.observaciones
. Se trata de un campo de tipotext
, El contenido de este campo se mostrará como una fila adicional desplegable en la renderización de datatables, tal cómo ya conocemos. En lo que al formulario del editor se refiere, este dato se grabará como untextarea
, para que veamos el funcionamiento.
EL SCRIPT PRIMARIO
El script primario se llaman articulo_editor_07.php
. Contiene, como ya es habitual, el objeto datatables, para la renderización de los datos en una tabla HTML, y el objeto editor que define el formulario para crear nuevos registros, editar los existentes, o eliminarlos. El listado es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Uso de DataTables</title> <!-- Font Awesome --> <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> <!-- jQuery UI --> <link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> <!-- Bootstrap 3 --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"> <!-- DataTables --> <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/dt/jszip-2.5.0/pdfmake-0.1.18/dt-1.10.12/af-2.1.2/b-1.2.2/b-colvis-1.2.2/b-flash-1.2.2/b-html5-1.2.2/b-print-1.2.2/cr-1.3.2/fc-3.2.2/fh-3.1.2/kt-2.1.3/r-2.1.0/rr-1.1.2/sc-1.4.2/se-1.2.0/datatables.min.css"/> <!-- El CSS del editor --> <link rel="stylesheet" type="text/css" href="editor/css/editor.dataTables.css"> </head> <body> <br> <div class="container"> <div class="row"> <div class="col-sm-12"> <table id="tabla_de_usuarios" class="table display table-striped table-bordered" width="100%"> <!-- Definimos la cabecera de la tabla HTML. Hay dos celdas que tienen id. Esto es porque a los datos que se alojarán en esas celdas les vamos a dar alineación derecha, de tal modo que a las celdas de cabecera les tendremos que forzar alineación izquierda para que el título quede a la izquierda y los contenidos a la derecha. Ya hemos hecho algo parceido en alguna ocasión anterior. --> <thead> <tr> <th> </th> <th>NOMBRE Y APELLIDOS</th> <th id="cabeceraDeAlta">F. ALTA</th> <th>GENERO</th> <th>ADM</th> <th id="cabeceraDeCreditos">CREDITOS</th> </tr> </thead> <tbody> </tbody> </table> </div> </div> </div> <!-- jQuery --> <script language="javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <!-- jQuery UI --> <script language="javascript" src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script> <!-- El JavaScript de DataTables --> <script type="text/javascript" src="https://cdn.datatables.net/v/dt/jszip-2.5.0/pdfmake-0.1.18/dt-1.10.13/af-2.1.3/b-1.2.4/b-colvis-1.2.4/b-flash-1.2.4/b-html5-1.2.4/b-print-1.2.4/cr-1.3.2/fc-3.2.2/fh-3.1.2/kt-2.2.0/r-2.1.0/rr-1.2.0/sc-1.4.2/se-1.2.0/datatables.min.js"></script> <!-- El JavaScript de BootStrap --> <script language="javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <!-- El JavaScript del editor --> <script type="text/javascript" src="editor/js/dataTables.editor.js"></script> <!-- La librería moment.js para fechas --> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js"></script> <!-- El código JavaScript --> <script language="javascript"> /* CREAMOS EL OBJETO EDITOR, PARA LAS FUNCIONES DE NUEVO, EDICIÓN Y ELIMINACIÓN DE REGISTROS. */ var objetoEditor = new $.fn.dataTable.Editor({ ajax: 'crud_editor_07.php', // El script que crea, actualiza o borra registros. table: '#tabla_de_usuarios', // La tabla sobre la que se actúa. idSrc: 'id', // El nombre del campo clave primaria de la tabla sobre la que se actúa. /* Las traducciones para los botones, los valores múltiples, el campo de fecha y la confirmación de eliminación. */ i18n: { create: { button: "Nuevo", title: "Crear nuevo registro", submit: "Grabar" }, edit: { button: "Editar", title: "Editar registro", submit: "Actualizar" }, remove: { button: "Borrar", title: "Borrar registro", submit: "Borrar", confirm: { _: "¿Estás seguro de eliminar estos %d registros?", 1: "¿Estás seguro de eliminar este registro?" } }, multi: { title: "Múltiples valores", info: "Los registros seleccionados contienen diversos valores para este campo. Para editar este campo con el mismo valor en los registros seleccionados, pulsa aquí. En caso conterario, los registros mantendrán sus valores individuales en este campo.", restore: "Restaurar los valores múltiples", noMulti: "Esta entrada puede ser modificada individualmente, pero no como parte de un grupo." }, datetime: { previous: 'Anterior', next: 'Siguiente', months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'], weekdays: ['Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb'] } }, /* La difinición de los campos del formulario. */ fields: [ /* ATENCIÓN. Los campos de tipo text se pueden definir sin especificar el tipo. El valor text es el tipo de campo por defecto. */ {label: 'Nombre:', name: 'nombre', attr: {class:'form-control'}}, {label: 'Apellidos:', name: 'apellidos', attr: {class:'form-control'}}, /* El campo de fecha con el datepicker jQueryUI, por funcionalidad. */ { label: 'F. Alta:', name: 'fecha_alta', type: 'date', def: function(){return new Date();}, dateFormat: 'dd-mm-yy', attr: {readonly:true, class:'form-control', style:'display:inline'}, opts:{ buttonImage:'editor/images/calendar.png', buttonImageOnly: true, buttonText: 'Elegir fecha', dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'], dayNamesMin: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sá'], dayNamesShort: ['Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb'], firstDay: 1, monthNames: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'], monthNamesShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'], changeMonth: true, changeYear: true, prevText: "Anterior", nextText: "Siguiente" } }, /* El campo relativo al género lo hemos incluido como botones de radio. Un campo de este tipo debe definir un botón de radio para cada posible valor que se deba poder almacenar en la tabla de la base de datos. Estos valores se definen bajo el epígrafe options. Cuando estamos editando, el valor se toma de la base de datos, de modo que la opción correspondiente ya aparece como checked. Cuando es un nuevo registro, aparecerá checked la opción que establecemos bajo el epígrafe def. Si es un nuevo registro y no se ha declarado def, no aparecerá ninguna opción checked. Es algo que deberemos comprobar antes de que se envíe el formulario (el evento preSubmit). Establecer un valor por defecto nos evita tener que hacer esa comprobación. */ { label: 'Género', name: 'genero', type: 'radio', options: [ {label: "Masculino", value: 'M'}, {label: "Femenino", value: 'F'} ], def: 'M' }, /* A continuación tenemos un campo de tipo checkbox. Este campo aparecerá marcado si el contenido del dato en la base de datos coincide con el valor que hemos puesto bajo options. Si no coincide la casilla aparecerá desmarcada. Ten en cuenta que si se envía el formulario con la casilla desmarcada, este campo no llegará al script de CRUD. Este comportamiento no es nada nuevo. En HTML puro ya se comportan así este tipo de campos. En el script de CRUP deberemos comprobar si aparece el dato y, en caso de no aparecer, considerar el valor a grabar en la base de datos. Observa el script de CRUD de este artículo para ver como está hecha esta comprobación. */ { label: "Es administrador", name: "es_administrador", type: "checkbox", options: [ {label: '', value: 'S'} ] }, /* El siguiente campo debe poder recibir, exclusivamente, un valor numérico. Como no existe un tipo de campo number en el editor, usaremos un campo de tipo text. Antes del envío del formulario (preSubmit), deberemos comprobar el valor de este campo. */ { label: 'Créditos:', name: 'creditos', attr: {class:'form-control text-right'}, fieldInfo: "Sólo números (-1 = créditos infinitos)." }, /* Aqui vemos un como funciona un campo de tipo textarea. */ { label: "Comentarios", name: "observaciones", type: "textarea" } ] // Fin de la definición de los campos }); /* FINAL DE LA DEFINICIÓN DE UN OBJETO EDITOR. */ objetoEditor.on('open', function(e, mode, action){ if (action == "remove") return; /* Recolocamos los campos que, visualmente, quedan muy altos respecto a sus correspondientes etiquetas. */ $("input:checkbox").css('margin-top', '10px'); $("textarea").css('margin-top', '10px'); }); objetoEditor.on('preSubmit', function(e, mode, action){ if (action == "remove") return true; /* Comprobamos que en el campo creditos haya un valor numérico y que este sea 0, un positivo o -1. Si esto no se cumple, se aborta el envío. */ var dato_creditos = objetoEditor.field('creditos').val(); if (!objetoEditor.field('creditos').isMultiValue()) dato_creditos = dato_creditos.trim(); if (dato_creditos == "" && !objetoEditor.field('creditos').isMultiValue()){ objetoEditor.field('creditos').error('Debes teclear los créditos correctos.'); objetoEditor.field('creditos').focus(); return false; } else { objetoEditor.field('creditos').error(''); } if (dato_creditos != parseFloat(dato_creditos).toFixed(0) && !objetoEditor.field('creditos').isMultiValue()){ objetoEditor.field('creditos').error('El dato de los créditos no tiene el formato correcto.'); objetoEditor.field('creditos').focus(); return false; } else { objetoEditor.field('creditos').error(''); } if (parseFloat(dato_creditos) < -1 && !objetoEditor.field('creditos').isMultiValue()){ objetoEditor.field('creditos').error('Indica los créditos, o -1 para infinitos.'); objetoEditor.field('creditos').focus(); return false; } else { objetoEditor.field('creditos').error(''); } return true; // Si todo ha ido bien, se retorna true para que se complete el envío. }); /* SE DEFINE EL OBJETO DATATABLES. SU USO ES, PRÁCTICAMENTE, EL MISMO QUE SIEMPRE, PARA RECUPERAR UN DATASET Y RENDERIZARLO EN LA PÁGINA. */ var objetoDataTables_usuarios = $('#tabla_de_usuarios').DataTable({ "language": { select: { rows: { _: "%d registros seleccionados", 0: "No se han seleccionado registros", 1: "1 registro seleccionado" } }, "emptyTable": "No hay datos disponibles en la tabla.", "info": "Del _START_ al _END_ de _TOTAL_ ", "infoEmpty": "Mostrando 0 registros de un total de 0.", "infoFiltered": "(filtrados de un total de _MAX_ registros)", "infoPostFix": "(actualizados)", "lengthMenu": "Mostrar _MENU_ registros", "loadingRecords": "Cargando...", "processing": "Procesando...", "search": "Buscar:", "searchPlaceholder": "Dato para buscar", "zeroRecords": "No se han encontrado coincidencias.", "paginate": { "first": "Primera", "last": "Última", "next": "Siguiente", "previous": "Anterior" }, "aria": { "sortAscending": "Ordenación ascendente", "sortDescending": "Ordenación descendente" } }, "lengthMenu": [[5, 10, 20, 25, 50, -1], [5, 10, 20, 25, 50, "Todos"]], "iDisplayLength": 10, "bServerSide": true, "sAjaxSource": "datos_externos_editor_07.php", // OJO. Ver el código para comprender. /* Definimos la operativa previa necesaria para cuatro columnas, de modo que se muestren de una forma "amigable", en lugar de los datos "en bruto". En primer lugar, en la columna que correesponde al nombre se muestra el nombre y los apellidos. En segundo lugar, en la columna que corresponde al género, como en la base de datos este aparece como M o F, se muestra "Masculino" o "Femenino". En la columna correspondiente a la prerrogativa de administrador, hacemos algo parecido, de modo que, en lugar de S o N nos muestre Sí o No. Por último, en la columna de créditos, si el valor es -1 lo hacemos aparecer como "infinitos", que es el criterio que hemos decidido para los usuarios que tienen créditos ilimitados (en un escenario real podrían ser, por ejemplo, los administradores). */ "columnDefs": [ { "targets": 1, "render": function (data, type, row) { return row['nombre']+' '+row['apellidos']; } }, { "targets": 3, "render": function (data, type, row) { return (data == 'M')?"Masculino":"Femenino"; } }, { "targets": 4, "render": function (data, type, row) { return (data == 'S')?"Sí":"No"; } }, { "targets": 5, "render": function (data, type, row) { return (data == '-1')?"Infinitos":data; } }, { "targets":6, visible: false } ], "columns" : [ { "className": 'celda_de_observaciones', "orderable": false, "data": null, "defaultContent": '<div class="text-center fa fa-plus-circle" style="width:100%; color: #3dc728;"></div>' }, {"data": 'nombre'}, {"data": 'fecha_alta', className: "text-right"}, {"data": 'genero'}, {"data": 'es_administrador'}, {"data": 'creditos', className: "text-right"}, {"data": 'apellidos'} ], "order": [1, 'asc'], dom: 'Bfrtipl', select: true, select: {style: 'single'}, buttons: [ {extend: 'create', editor: objetoEditor}, {extend: 'edit', editor: objetoEditor}, {extend: 'remove', editor: objetoEditor} ] }); $('label').addClass('form-inline'); $('select, input[type="search"]').addClass('form-control input-sm'); $('#cabeceraDeCreditos').removeClass("text-right"); $('#cabeceraDeAlta').removeClass("text-right"); $('#tabla_de_usuarios tbody').on('click', 'td.celda_de_observaciones', function () { var filaDeLaTabla = $(this).closest('tr'); var filaComplementaria = objetoDataTables_usuarios.row(filaDeLaTabla); var celdaDeIcono = $(this).closest('td.celda_de_observaciones'); if (filaComplementaria.child.isShown() ) { // La fila complementaria está abierta y se cierra. filaComplementaria.child.hide(); celdaDeIcono.html('<div class="text-center fa fa-plus-circle" style="width:100%; color: #3dc728;"></div>'); } else { // La fila complementaria está cerrada y se abre. filaComplementaria.child(formatearSalidaDeDatosComplementarios(filaComplementaria.data(), 'observaciones')).show(); celdaDeIcono.html('<div class="text-center fa fa-minus-circle" style="width:100%; color: #e80909;"></div>'); } }); function formatearSalidaDeDatosComplementarios (filaDelDataSet, columna) { var cadenaDeRetorno = ''; cadenaDeRetorno += '<div>'; if (filaDelDataSet[columna] == ''){ cadenaDeRetorno = 'Este usuario no tiene comentarios.'; } else { cadenaDeRetorno += 'COMENTARIOS: ' + filaDelDataSet[columna]; } cadenaDeRetorno += '</div>'; return cadenaDeRetorno; } </script> </body> </html> |
Si bien el listado ya incluye suficientes comentarios para poder entender como opera cada parte del código, vamos a tratar de ser un poco más específicos en algunos puntos concretos.
En primer lugar, fíjate en la forma en que definimos un campo formado por botones de radio, entre las líneas 141
y 150
. Definimos el campo como un conjunto de botones de radio. Para ello, lo declaramos así:
type: 'radio',
Cada uno de los botones se define bajo el epígrafe options
, indicando dos parámetros: label
será la etiqueta que se verá en el formulario junto al botón de radio que estamos definiendo, mientras que value
será el valor que recibirá el campo si ese botón está activado.
options: [
{label: "Masculino", value: 'M'},
{label: "Femenino", value: 'F'}
],
Este tipo de botones, por su propia naturaleza, son adecuados para campos de tipo enum
, que pueden tener un número discreto de posibilidades. Debe haber un botón de radio por cada posible valor que pueda tener el campo enum
y el atributo value
de dicho botón debe coincidir con uno de los posibles valores del campo enum
. Así, tenga el campo el valor que tenga, se activará el correspondiente botón de radio cuando abramos el formulario para editar. Dicho de otro modo: en nuestro ejemplo, el campo genero
de la tabla usuarios
siempre tendrá el valor M
o el valor F
. Así pues, cuando abramos el formulario del editor para modificar los datos de un registro, aparecerá activado el correspondiente botón de radio. Si tuvieran unos valores distintos de los posibles valores del campo enum
(por ejemplo, si a los botones de radio les hubiéramos aplicado los valores, digamos, masc
y fem
) no sería posible que se activará el adecuado de forma automática, y aparecerían los dos desactivados, lo que no nos conviene.
Además, tenemos el parámetro def
, que permite establecer que botón de radio se activará por defecto cuando estemos creando un nuevo usuario. El que escojamos es irrelevante. El hecho es que haya siempre uno activado por defecto, para evitar tener que comprobarlo al enviar el formulario. Así, ya estamos forzando al usuario a escoger una opción. Es una forma de decirle: “si no escoges tú, escojo yo, pero hay que escoger”.
En las líneas de la 160
a la 167
vemos como definimos un campo de tipo casilla de texto. Estos campos son adecuados cuando se refieren a un campo de la base de datos, de tipo enum
, que puede tener dos posibles valores, y sólo dos. En el caso de nuestro ejemplo, es claramente una buena opción. Un usuario es administrador, o no lo es. Hay que escoger una opción y sólo una. También serían adecuados si hubiera una colección de estas casillas, y se refiriesen a distintos campos de este tipo. Es decir, en general, un campo de tipo checkbox
es adecuado en las mismas circunstancias que lo usaríamos en un formulario HTML convencional.
En el epígrafe options
se puede establecer una etiqueta para cada casilla, aunque, en este ejemplo, la hemos dejado en blanco. El valor establecido en value
debe coincidir con uno de los dos posibles valores en el campo enum
de la tabla. Así, si el campo tiene ese valor, aparecerá la casilla marcada por defecto. Si tiene el otro valor, aparecerá desmarcada.
En las líneas 180
a 184
ves cómo se define un campo de tipo textarea
, de una forma simple. En posteriores artículos veremos como configurar interesantes opciones de este tipo de campos.
Quiero llamar tu atención a la finalidad que le damos aquí al evento preOpen
del formulario. El uso de este evento ya no es nuevo. Aquí lo hemos empleado para ajustar la altura de las etiquetas de los botones de radio y checkbox, para mejorar el aspecto visual, como puedes ver en las líneas 192
y 193
.
El evento preSubmit
lo hemos usado para que, antes de enviar un formulario de edición o de nuevo registro, se compruebe que en el campo créditos hay un valor numérico válido. Esto es -1
(lo que, como hemos acordado, significa créditos infinitos), 0
(ningún crédito) o un valor positivo. Ya hicimos algo parecido en artículos anteriores de esta serie con los salarios de una tabla de personal, así que, realmente, tampoco nada nuevo por aquí.
EL SCRIPT DE CRUD
El script destinado a responder al formulario del editor se llama crud_editor_07.php
y su listado es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
<?php // Establecemos la codificacion para las llamadas y respuestas HTTP mb_internal_encoding ('UTF-8'); /* CREAMOS LA CONEXION A LA BASE DE DATOS, O BIEN LA IMPORTAMOS DESDE UN ARCHIVO EXTERNO DE CONFIGURACION. */ include ('conexion_bd_editor.php'); /* RECUPERAMOS TODOS LOS PARAMETROS DE $_POST. LOS QUE NO APAREZCAN EN LA CONSULTA RECIBIRAN UN VALOR PREDETERMINADO. ESTOS DATOS SON LOS QUE SE RECIBEN CADA VEZ QUE EL EDITOR DE DATATABLES LLAMA A ESTE SCRIPT. */ $datosDeLlamada = $_POST; /* Si la casilla de checkbox se ha enviado desmarcada, no existe niguna varible relativa a la misma. En ese caso le daremos el valor 'N'. Cuando la casilla ha sido marcada se recibe con el valor que la definimos. Sin embargo, este valor no vuelve como una cadena, sino como una matriz de la que tenemos que recuperar el elemento correspondiente al índice. Esto es así porque un mismo campo puede implicar a varias casillas. Sin embargo, como aquí el campo sólo implica a una casilla, nos vale con comprobar si la variable existe o no, y, en cada caso, sustituirla por un valor. Realmente, si existe, de cada dato no nos llega $data["es_administrador"] = "S", sino $data["es_administrador"][0] = "S", donde el índice será 0, si hay una casilla, 0 y 1 si hay dos, etcetera. Esto de la matriz lo veremos más claro en un ejemplo posterior, ya que, así, a pelo, es difícil de comprender. */ foreach ($datosDeLlamada["data"] as $keyData=>$data) $datosDeLlamada["data"][$keyData]["es_administrador"] = (isset($data["es_administrador"]))?"S":"N"; /* SE INDICA(N) LA(S) TABLA(S) QUE SE VA(N) A USAR EN LA CONSULTA. */ $tablasDeBBDD = array( 'usuarios' ); /* SE DEFINE LA LISTA DE COLUMNAS QUE SE DEVOLVERON PARA SER MOSTRADAS EN LA TABLA HTML. LOS NOMBRES DE ESTAS COLUMNAS DEBEN COINCIDIR CON LOS DE LAS COLUMNAS DE LA(S) TABLA(S) AFECTADA(S) POR LA CONSULTA. */ $columnasDeDatos = array( $tablasDeBBDD[0].'.id', $tablasDeBBDD[0].'.nombre', $tablasDeBBDD[0].'.fecha_alta', $tablasDeBBDD[0].'.genero', $tablasDeBBDD[0].'.es_administrador', $tablasDeBBDD[0].'.creditos', $tablasDeBBDD[0].'.apellidos', $tablasDeBBDD[0].'.observaciones' ); /* Se determina qué es lo que se va a hacer. Esto viene por POST en la variable "action". Puede ser remove, edit o create. En cada caso se llevara a cabo la acción elegida, sobre los registros que estuvieran seleccionados. Además, se prepara la respuesta adecuada para devolver al script primario. */ $data = array(); switch ($datosDeLlamada["action"]){ case "remove": /* Si es una eliminación debemos borrar el usuario en la tabla de usuarios. */ foreach ($datosDeLlamada["data"] as $keyReg=>$registro){ $consulta = "DELETE FROM ".$tablasDeBBDD[0]." "; $consulta .= "WHERE ".$columnasDeDatos[0]."='".$keyReg."';"; $conexion->query($consulta); } break; case "edit": /* Cuando se procesa una edición de modifican directamente los campos de la tabla de usuarios. */ foreach ($datosDeLlamada["data"] as $keyReg=>$registro){ $consulta = "UPDATE ".$tablasDeBBDD[0]." SET "; $consulta .= $columnasDeDatos[1]."='".$registro["nombre"]."', "; $consulta .= $columnasDeDatos[6]."='".$registro["apellidos"]."', "; $consulta .= $columnasDeDatos[2]."='".date("Y-m-d", strtotime($registro["fecha_alta"]))."', "; $consulta .= $columnasDeDatos[3]."='".$registro["genero"]."', "; $consulta .= $columnasDeDatos[4]."='".$registro["es_administrador"]."', "; $consulta .= $columnasDeDatos[5]."='".$registro["creditos"]."', "; $consulta .= $columnasDeDatos[7]."='".$registro["observaciones"]."' "; $consulta .= "WHERE ".$columnasDeDatos[0]."='".$keyReg."';"; $conexion->query($consulta); $elemento = array("id"=>$keyReg); foreach ($registro as $keyItem=>$item) $elemento[$keyItem] = $item; $data[] = $elemento; } break; case "create": /* Para la creación de un nuevo usuario, simplemente creamos el registro del mismo en la tabla de usuarios. */ $consulta = "INSERT INTO ".$tablasDeBBDD[0]." ("; $consulta .= $columnasDeDatos[1].", "; // nombre $consulta .= $columnasDeDatos[2].", "; // fecha_alta $consulta .= $columnasDeDatos[3].", "; // genero $consulta .= $columnasDeDatos[4].", "; // es_administrador $consulta .= $columnasDeDatos[5].", "; // creditos $consulta .= $columnasDeDatos[6].", "; // apellidos $consulta .= $columnasDeDatos[7]; // observaciones $consulta .= ") VALUES ("; $consulta .= "'".$datosDeLlamada["data"][1]["nombre"]."', "; // nombre $consulta .= "'".date("Y-m-d", strtotime($datosDeLlamada["data"][2]["fecha_alta"]))."', "; // fecha_alta $consulta .= "'".$datosDeLlamada["data"][3]["genero"]."', "; // genero $consulta .= "'".$datosDeLlamada["data"][4]["es_administrador"]."', "; // es_administrador $consulta .= "'".$datosDeLlamada["data"][5]["creditos"]."', "; // creditos $consulta .= "'".$datosDeLlamada["data"][6]["apellidos"]."', "; // apellidos $consulta .= "'".$datosDeLlamada["data"][7]["observaciones"]."', "; // observaciones $consulta .= ");"; $conexion->query($consulta); $elemento = array("id"=>$conexion->lastInsertId()); foreach ($datosDeLlamada["data"][0] as $keyItem=>$item) $elemento[$keyItem] = $item; $data[] = $elemento; break; } $datosParaDevolver = array("data"=>$data); $resultado = json_encode($datosParaDevolver); echo $resultado; ?> |
Realmente, donde tenemos que fijarnos es en las líneas que aparecen resaltadas. Cuando nuestro formulario incluye (como es el caso de este ejercicio), casillas de checkbox, estas llegan como una matriz. Así por ejemplo, en nuestro listado primario el campo es_administrador va a llegar como una matriz de un solo elemento (ya que sólo tiene una casilla). Pero es que, además, si la casilla no está checada, el elemento, simplemente, no es enviado. Así pues, debemos determinar si el elemento ha llegado (lo que implicaría casilla checada) o no (lo que implicaría casilla no checada). Con una sola casilla checkbox es difícil comprender esta operativa. En un artículo posterior veremos ejemplos con más de una casilla checkbox por campo, lo que nos permitirá analizar a fondo la forma en que se transmiten este tipo de datos.
Por lo demás, el resto del script es cómo ya lo conocemos.
CONSIDERACIONES FINALES
En cuanto al script que lee los datos para el datatables, no hay nada de nuevo. Su operativa es ya de sobra conocida. En este enlace tienes los scripts y la base de datos que hemos empleado en este ejercicio.