En este artículo vamos a dar un paso más en el uso del plugin DataTables. Vamos a ver que hay ciertos métodos que nos permiten realizar búsquedas de determinados registros de forma programática, buscando, por ejemplo, sólo por determinados criterios. Así, aunque todas las columnas de nuestra tabla sean searchables, podremos buscar un contenido específico en una o más de ellas, ignorando si ese contenido está o no en las demás.
Esto nos permitirá programar búsquedas totalmente personalizables, usando los scripts que aquí veremos como guía para adaptarlos a nuestras necesidades.
BÚSQUEDAS SELECTIVAS
En este apartado vamos a ver cómo realizar búsquedas de un dato en columnas concretas. Por ejemplo, puede que en nuestra tabla de personal (vamos a usar una muy parecida a la de ejemplos anteriores) queramos buscar algo en la columna nombre, pero no en las demás, aunque, en prioncipio, estén programadas como searchables. Una vez más, tenemos dos scripts. El principal, que implementa el plugin DataTables y renderiza la tabla de resultados y el secundario, que selecciona los datos que serán devueltos al principal.
Hemos modificado la tabla para que haya tres miembros del personal cuyo apellido sea York
. Esto lo hemos hecho para poder ver como se busca la palabra york
en el apellido (lo que nos dará los miembros con dicho apellido) o en la ciudad (lo que nos devolverá a los miembros de esta empresa que residen en Nueva York
). Tú en tu tabla puedes modificar los apellidos de los miembros que desees para esta prueba.
EL SCRIPT PRINCIPAL
Esta vez el script principal tiene varias cosas nuevas, a las que vamos a prestar atención. Lo hemos llamado articulo_07.php
y su listado es el que vemos a continuación:
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 |
<!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> <!-- El CSS de 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 de Bootstrap --> <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">--> </head> <body> <div class="container"> <div class="row"><br></div> <header> <div class="row"> <div class="col-sm-2"><label for="id_campo">Buscar en campo:</label></div> <div class="col-sm-2"> <select class="form-control input-sm" id="id_campo"> <option value="0" selected>NOMBRE</option> <option value="1">APELLIDO</option> <option value="2">CARGO</option> <option value="3">CIUDAD</option> <option value="4">INGRESO</option> <option value="5">SALARIO</option> </select> </div> <div class="col-sm-2"> <select class="form-control input-sm" id="id_operacion"> <option value="0" selected>Es igual a</option> <option value="1">No es igual a</option> <option value="2">Contiene</option> <option value="3">No contiene</option> <option value="4">Empieza por</option> <option value="5">No empieza por</option> <option value="6">Acaba por</option> <option value="7">No acaba por</option> <option value="8">Es menor que</option> <option value="9">Es menor o igual que</option> <option value="10">Es mayor que</option> <option value="11">Es mayor o igual que</option> </select> </div> <div class="col-sm-2"> <input type="text" class="form-control input-sm" id="valor_a_comparar"> </div> <div class="col-sm-2"> <input type="button" class="btn btn-primary btn-sm" id="boton_buscar" value="Buscar" disabled> </div> <div class="col-sm-2"> <input type="button" class="btn btn-warning btn-sm" id="boton_resetear" value="Resetear búsqueda" disabled> </div> </div> </header> <div class="row"><br></div> <div class="row"> <div class="col-sm-12"> <table id="tabla_de_personal" class="table display table-striped table-bordered"> <thead> <tr> <th>NOMBRE</th> <th>APELLIDO</th> <th>CARGO</th> <th>CIUDAD</th> <th>INGRESO</th> <th>SALARIO</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> <!-- El JavaScript de DataTables --> <script language="javascript" type="text/javascript" src="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.js"></script> <!-- El JavaScript de BootStrap --> <script language="javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <!-- El código JavaScript --> <script language="javascript"> var objetoDataTables_personal = $('#tabla_de_personal').DataTable({ "language": { "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_07.php", "columns" : [ {"data": 0}, {"data": 1}, {"data": 2}, {"data": 3}, {"data": 4}, {"data": 5} ], }); $('label').addClass('form-inline'); $('select, input[type="search"]').addClass('form-control input-sm'); /* Comprobamos si se activa o desactiva el botón de búsqueda personalizada y el de reseteo. */ $('#valor_a_comparar').on('keyup keypress change', function(){ $('#boton_buscar').prop('disabled', ($('#valor_a_comparar').prop('value') == "")); $('#boton_resetear').prop('disabled', ($('#id_campo').prop('value') == "0" && $('#id_operacion').prop('value') == "0" && $('#id_campo').prop('value') == "")); }); $('#id_campo, #id_operacion').on('change', function(){ $('#boton_resetear').prop('disabled', ($('#id_campo').prop('value') == "0" && $('#id_operacion').prop('value') == "0" && $('#valor_a_comparar').prop('value') == "")); }); /* Si se pulsa el botón de reset. */ $('#boton_resetear').on('click', function(){ $('#id_campo, #id_operacion').prop('value', '0'); $('#valor_a_comparar').prop('value', ''); $('#boton_buscar').prop('disabled', true); $('#boton_resetear').prop('disabled', true); objetoDataTables_personal .columns([0,1,2,3,4,5]) .search('') .draw(); }); /* Cuando se pulsa el botón de búsqueda se construye la recla de búsqueda según se ha solicitado. */ $('#boton_buscar').on('click', function(){ var clausula = ""; switch ($('#id_operacion').prop('value')) { case '0': clausula = " = '" + $('#valor_a_comparar').prop('value') + "' "; // Es igual a lo que hay en el campo de texto break; case '1': clausula = " != '" + $('#valor_a_comparar').prop('value') + "' "; // No es igual a lo que hay en el campo de texto break; case '2': clausula = " LIKE '%" + $('#valor_a_comparar').prop('value') + "%' "; // Contiene lo que hay en el campo de texto break; case '3': clausula = " NOT LIKE '%" + $('#valor_a_comparar').prop('value') + "%' "; // No contiene lo que hay en el campo de texto break; case '4': clausula = " LIKE '" + $('#valor_a_comparar').prop('value') + "%' "; // Empieza por lo que hay en el campo de texto break; case '5': clausula = " NOT LIKE '" + $('#valor_a_comparar').prop('value') + "%' "; // No empieza por lo que hay en el campo de texto break; case '6': clausula = " LIKE '%" + $('#valor_a_comparar').prop('value') + "' "; // Acaba por lo que hay en el campo de texto break; case '7': clausula = " NOT LIKE '%" + $('#valor_a_comparar').prop('value') + "' "; // No acaba por lo que hay en el campo de texto break; case '8': clausula = " < '" + $('#valor_a_comparar').prop('value') + "' "; // Es menor que lo que hay en el campo de texto break; case '9': clausula = " <= '" + $('#valor_a_comparar').prop('value') + "' "; // Es menor o igual que lo que hay en el campo de texto break; case '10': clausula = " > '" + $('#valor_a_comparar').prop('value') + "' "; // Es mayor que lo que hay en el campo de texto break; case '11': clausula = " >= '" + $('#valor_a_comparar').prop('value') + "' "; // Es mayor o igual que lo que hay en el campo de texto break; } objetoDataTables_personal .columns([0,1,2,3,4,5]) .search('') .column($('#id_campo').prop('value')) .search(clausula) .draw(); }); </script> </body> </html> |
Las novedades en este código están en los dos grupos de líneas que hay resaltadas. En el primer grupo creamos un formulario para realizar búsquedas personalizadas. El formulario en sí no tiene nada que no conozcas. Como ves, son dos selectores, para indicar cual es el campo por el que queremos buscar y el criterio. En un campo de texto tecleamos el valor que queremos buscar. También tenemos dos botones: uno para efectuar la búsqueda indicada y el otro para resetear los campos de búsqueda y volver a obtener todos los registros. Si estás familiarizado (y así lo supongo, si estás leyendo esto) con HTML y bootstrap, este formulario no presenta ninguna dificultad para ser comprendido.
La gracia la tienes en el segundo bloque resaltado. Y aquí hay dos grupos de novedades. Por una parte, el jQuery necesario para gestionar el formulario del que hablábamos hace un momento. Por ejemplo, cuando tecleas lo que sea en el campo de texto, se comprueba si está vacío o no, para activar o desactivar, según proceda, los botones del formulario. Esta parte tampoco tiene nada extraño si estás familiarizado con jQuery (una vez más, así lo supongo).
Por otro lado, está la ejecución de las búsquedas en sí. Cuando se pulsa uno de los botones del formulario se actúa sobre el objeto que hemos creado con DataTables (en el código se llama objetoDataTables_personal
). Observa cómo lo creamos, al igual que en el artículo anterior. Está en la línea 87
:
var objetoDataTables_personal = $('#tabla_de_personal').DataTable({
Lo que hacemos es usar cuatro métodos del plugin DataTables:
- El método
columns()
indica que vamos a actuar sobre un conjunto de columnas, cuyos índices se definen entre corchetes, como en una matriz. Lo vemos en la línea188
:.columns([0,1,2,3,4,5])
. - El método
search()
. Recibe un argumento y lo pasa a las columnas indicadas en el anterior para buscar el argumento en las columnas especificadas. Así, en la línea189
vemos:.search('')
. Esto hace que se busque la cadena vacía en todas las columnas, de modo que, realmente, se emplea para limpiar cualquier búsqueda que pudiera haber de antes. - El método
column()
es similar acolumns()
pero para referirse a una sola columna. Cuando vamos a buscar algo en una columna, a este método le pasamos el índice de la columna en la que vamos a buscar. Lo vemos en la línea190
:.column($('#id_campo').prop('value'))
. Como ves, nos referimos a la columna cuyo índice está seleccionado en el combo correspondiente del formulario superior. - De nuevo usamos el método
search()
. Esta vez le pasamos, cómo argumento, una claúsula SQL que se ha creado dinámicamente al pulsar el botón de Búsqueda. Lo vemos en la línea191
:.search(clausula)
. - Con los métodos anteriores le decimos al plugin lo que tiene que buscar, pero ahora tenemos que hacer que llame al script secundario, pasándole esa claúsula SQL y el índice de la columna sobre la que queremos hacer la búsqueda, y que, con los resultados obtenidos, renderice de nuevo la tabla. Esto lo hacemos con el método
draw()
, cómo puedes ver en la línea194
.
Por lo tanto, cuando seleccionamos un campo y un criterio, establecemos un valor de búsqueda, y pulsamos el botón correspondiente, ocurren las siguientes acciones:
- En primer lugar se crea una claúsula SQL en base al criterio buscado y al valor tecleado en el campo. Esta claúsula se crea como texto plano, y su creación en sí no tiene nada de nuevo. Solo es analizar el criterio mediante switch y crear la cadena con el operador SQL y el valor del campo de texto.
- A continuación se ejecutan los métodos del objeto DataTables que hemos visto anteriormente, encadenándolos uno detrás de otro, mediante el operador punto (
.
). Se seleccionan todas las columnas, y se envía una búsqueda con una cadena vacía, para limpiar cualquier búsqueda anterior; se selecciona la columna que se haaya elegido en el selector y se envía la claúsula que acabamos de componer; por último, se redibuja la tabla con los datos actualizados.
Todo esto suena un poco críptico en principio pero, una vez que analizas con detalle el código, y lo pruebas un par de veces, en seguida ves cómo actúa. Como te mencionaba arriba, vamos a buscar el texto York
en el campo APELLIDO
. El formulario queda así:
Pulsamos el botón de búsqueda y nos devuelve aquellos miembros de la plantilla cuyo apellido sea York
. En mi caso, se lo he puesto a tres personas, que son las que me aparecen.
Ahora vamos a cambiar un poco el criterio. Selecciona el campo CIUDAD
y el criterio Contiene
. El formulario queda así:
Al pulsar el botón de búsqueda, nos aparecen todas las personas cuya ciudad es New York.
ATENCIÓN. Es importante que entiendas cómo comunica el plugin al script secundario el campo de búsqueda cuando usamos los métodos column() y search() . Los campos tienen un índice que coincide con el orden en que están definidas las cabeceras de la tabla HTML y las columnas en el script secundario. Cuando se ejecutan estos métodos (de hecho no se ejecutan realmente hasta que llegamos al método draw() ) se envía un valor sSearch_n , donde n es el número de columna (ya mencionamos de pasada estas variables en el artículo V de esta serie). Las columnas empiezan a contar por 0 . Como tenemos en la tabla seis columnas, en la llamada al script secundario le pasamos seis variables por get al script secundario (sSearch_0 , sSearch_1 , sSearch_2 , sSearch_3 , sSearch_4 y sSearch_5 ). Lo bueno es que el plugin pone el argumento de search() en la variable que corresponde al índice establecido en column() . Así, si tenemos una llamada a .column(1).search(" = york ") (cómo en el primer ejemplo), lo que se hacer es guardar la claúsula en la variable sSearch_1 , mientras que las demás van sin contenido. Será el script secundario el que lea estas variables, como veremos. La llamada que hacemos para borrar búsquedas anteriores, .columns([0, 1, 2, 3, 4, 5]).search('') , lo que hace es enviar las seis variables sin contenido. |
EL SCRIPT SECUNDARIO
El script secundario también ha sufrido algunas modificaciones, aunque menores. Vemos el listado en datos_externos_o7.php
:
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 |
<?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. */ $conexion = new PDO('mysql:host=localhost;dbname=datatables;charset=UTF8', 'root', ''); $conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); /* RECUPERAMOS TODOS LOS PARAMETROS DE $_GET. LOS QUE NO APAREZCAN EN LA CONSULTA RECIBIRAN UN VALOR PREDETERMINADO. ESTOS DATOS SON LOS QUE SE RECIBEN CADA VEZ QUE EL PLUGIN DATATABLES LLAMA A ESTE SCRIPT. */ $datosDeLlamada = $_GET; /* SE INDICA(N) LA(S) TABLA(S) QUE SE VA(N) A USAR EN LA CONSULTA. */ $tablasDeBBDD = array( 'personal', 'ciudades', 'cargos' ); /* 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. */ $columnasParaRetorno = array( $tablasDeBBDD[0].'.nombre', $tablasDeBBDD[0].'.apellido', $tablasDeBBDD[2].'.cargo', $tablasDeBBDD[1].'.ciudad', $tablasDeBBDD[0].'.fecha_de_ingreso', $tablasDeBBDD[0].'.salario_bruto_anual' ); $numeroDeColumnas = count($columnasParaRetorno); //////////////////////////////////////////////// REGLAS DE FILTRADO //////////////////////////// /* PREPARAMOS EL FILTRADO POR COLUMNAS PARA LA CAJA DE BUSQUEDA */ $reglasDeFiltradoDeUsuario = array (); if (isset($datosDeLlamada['sSearch']) && $datosDeLlamada['sSearch'] !== "") { for($i = 0; $i < $numeroDeColumnas; $i++) { if (isset ($datosDeLlamada['bSearchable_'.$i]) && $datosDeLlamada['bSearchable_'.$i] == 'true') { $reglasDeFiltradoDeUsuario[] = $columnasParaRetorno[$i]." LIKE '%".addslashes($datosDeLlamada['sSearch'])."%'"; } } } if (!empty($reglasDeFiltradoDeUsuario)){ $reglasDeFiltradoDeUsuario = ' ('.implode(" OR ", $reglasDeFiltradoDeUsuario).') '; } else { $reglasDeFiltradoDeUsuario = ''; } /* PREPARAMOS LAS REGLAS DE FILTRADO PARA LAS BUSQUEDAS PROGRAMADAS POR METODO .search() (BÚSQUEDAS PERSONALIDAS DEL USUARIO). */ $reglasDeBusquedaPorProgramacion = array(); for($i = 0; $i < $numeroDeColumnas; $i++) { if (isset($datosDeLlamada['sSearch_'.$i]) && $datosDeLlamada['sSearch_'.$i] !== ""){ $reglasDeBusquedaPorProgramacion[] = $columnasParaRetorno[$i].$datosDeLlamada['sSearch_'.$i]; } } if (!empty($reglasDeBusquedaPorProgramacion)){ $reglasDeBusquedaPorProgramacion = ' ('.implode(" AND ", $reglasDeBusquedaPorProgramacion).') '; } else { $reglasDeBusquedaPorProgramacion = ''; } /* PREPARAMOS LAS REGLAS DE FILTRADO DE RELACIONES ENTRE TABLAS. ESTAS SE PROGRAMAN AQUI A MANO, PORQUE PUEDEN EXISTIR O NO, DEPENDIENDO DE QUE SE USE UNA TABLA O MAS DE UNA. */ $reglasDeFiltradoDeRelaciones = ''; $reglasDeFiltradoDeRelaciones .= " (".$tablasDeBBDD[1].".id = ".$tablasDeBBDD[0].".id_ciudad "; $reglasDeFiltradoDeRelaciones .= "AND ".$tablasDeBBDD[2].".id = ".$tablasDeBBDD[0].".id_cargo) "; /* SE COMPONE TODA LA REGLA DE FILTRADO. EN ESTE CASO INCLUYE LAS CLAÚSULAS DE BÚSQUEDA, Y LAS RELACIONES ENTRE TABLAS. SIGUE SIENDO UN EJEMPLO SIMPLE, PERO MÁS ELABORADO QUE EL ANTERIOR. MÁS ADELANTE VEREMOS OTROS USOS. LO IMPORTANTE AQUI ES QUE, ADEMÁS DE LAS CLAUSULAS DE BÚSQUEDA (VARIABLE $reglasDeFiltradoDeUsuario, QUE PUEDEN EXISTIR O NO) TAMBIÉN HAY UNA CLAÚSULA DE RELACIONES ENTRE LAS TABLAS. SI HAY MÁS DE UNA TABLA SIEMPRE HABRÁ UNA CLAÚSULA DE RELACIONES ($reglasDeFiltradoDeRelaciones). LAS IMPLEMENTAMOS COMO UNA MATRIZ PARA PODER COMPROBAR LAS QUE EXISTEN Y LAS QUE NO, Y LUEGO LAS UNIMOS CON EL OPERADOR AND, SI HAY MÁS DE UNA CLAÚSULA DE FILTRADO. */ $reglasDeFiltrado = array(); if ($reglasDeFiltradoDeUsuario > '') $reglasDeFiltrado[] = $reglasDeFiltradoDeUsuario; if ($reglasDeFiltradoDeRelaciones > '') $reglasDeFiltrado[] = $reglasDeFiltradoDeRelaciones; if ($reglasDeBusquedaPorProgramacion > '') $reglasDeFiltrado[] = $reglasDeBusquedaPorProgramacion; $reglasDeFiltrado = implode(" AND ", $reglasDeFiltrado); //////////////////////////////////////////// FIN DE REGLAS DE FILTRADO /////////////////////////// /////////////////////////// REGLAS DE ORDENACION //////////////////////// /* SE COMPONE LA REGLA DE ORDENACION. */ $reglasDeOrdenacion = array (); if (isset($datosDeLlamada['iSortCol_0'] )) { $columnasDeOrdenacion = intval($datosDeLlamada['iSortingCols']); for($i = 0; $i < $columnasDeOrdenacion; $i ++) { if ($datosDeLlamada['bSortable_'.intval($datosDeLlamada['iSortCol_'.$i])] == 'true') { $reglasDeOrdenacion [] = $columnasParaRetorno[intval($datosDeLlamada['iSortCol_'.$i])].($datosDeLlamada['sSortDir_'.$i] === 'asc'?' asc':' desc'); } } } if (!empty($reglasDeOrdenacion)) { $reglasDeOrdenacion = " ORDER BY ".implode(", ", $reglasDeOrdenacion); } else { $reglasDeOrdenacion = ""; } /* SE COMPONE LA REGLA DE LIMITACION DE REGISTROS. */ $reglaDeLimitacion = ($datosDeLlamada['iDisplayLength'] > 0)?' LIMIT '.$datosDeLlamada['iDisplayStart'].', '.$datosDeLlamada['iDisplayLength'].';':';'; /////////////////////////////////////// FIN DE REGLAS DE ORDENACION //////////////////// /* SE PREPARA LA CONSULTA DE RECUPERACION DEL DATASET SOLICITADO. */ $consulta = "SELECT ".implode(', ', $columnasParaRetorno)." "; $consulta .= "FROM ".implode(', ', $tablasDeBBDD)." "; $consulta .= "WHERE 1 "; if ($reglasDeFiltrado > "") $consulta .= "AND (".$reglasDeFiltrado.") "; $consulta .= $reglasDeOrdenacion; $consulta .= $reglaDeLimitacion; $hacerConsulta = $conexion->prepare($consulta); $hacerConsulta->execute(); $DataSet = $hacerConsulta->fetchAll(PDO::FETCH_ASSOC); $hacerConsulta->closeCursor(); /* SI ES NECESARIO ADAPTAR ALGUN DATO PARA PRESENTACION, SE ADAPTA AQUI. SI ES NECESARIOS AGREGAR ENLACES, REFERENCIAS A IMAGENES, O CUALQUIER OTRA COSA, SE INCLUYE EN ESTA SECCION. EN ESTE CASO, LO ÚNICO QUE VAMOS A HACER ES DARLE FORMATO AL SALARIO ANUAL. */ foreach ($DataSet as $keyDL=>$DL){ $DataSet[$keyDL]['fecha_de_ingreso'] = date("d-m-Y", strtotime($DL['fecha_de_ingreso'])); $DataSet[$keyDL]['salario_bruto_anual'] = number_format($DL['salario_bruto_anual'], 2, ",", ".").' €'; } /* CALCULO DE DATOS INFORMATIVOS DE REGISTROS. */ $numeroDeRegistrosDelDataSet = count($DataSet); /* CALCULO DEL TOTAL DE REGISTROS QUE CUMPLEN LAS REGLAS DE FILTRADO SIN ORDENACION NI LIMITACION. */ $consulta = "SELECT COUNT(".$columnasParaRetorno[0].") "; $consulta .= "FROM ".implode(', ', $tablasDeBBDD)." "; $consulta .= "WHERE 1 "; if ($reglasDeFiltrado > "") $consulta .= "AND (".$reglasDeFiltrado.") "; $hacerConsulta = $conexion->prepare($consulta); $hacerConsulta->execute(); $totalDeRegistrosConFiltrado = $hacerConsulta->fetch(PDO::FETCH_NUM)[0]; $hacerConsulta->closeCursor(); /* TOTAL DE REGISTROS DE LA TABLA PRIMARIA (O UNICA, SI SOLO HAY UNA). */ $consulta = "SELECT COUNT(".$columnasParaRetorno[0].") "; $consulta .= "FROM ".$tablasDeBBDD[0].";"; $hacerConsulta = $conexion->prepare($consulta); $hacerConsulta->execute(); $totalDeRegistrosEnBruto = $hacerConsulta->fetch(PDO::FETCH_NUM)[0]; $hacerConsulta->closeCursor(); // SE PREPARA UNA MATRIZ CON TODOS LOS DATOS NECESARIOS PARA LA SALIDA. $matrizDeSalida = array( "sEcho" => intval($datosDeLlamada['sEcho']), "iTotalRecords" => strval($totalDeRegistrosEnBruto), "iTotalDisplayRecords" => strval($totalDeRegistrosConFiltrado), "aaData" => array () ); foreach ($DataSet as $DL){ $registro = array(); foreach ($DL as $dato) $registro[] = $dato; $matrizDeSalida['aaData'][] = $registro; unset($registro); } $salidaDeDataSet = json_encode ($matrizDeSalida, JSON_HEX_QUOT); /* SE DEVUELVE LA SALIDA */ echo $salidaDeDataSet; ?> |
Las modificaciones aquí están destinadas a reconocer las variables sSearch_n
y hacer lo necesario con ellas.
En primer lugar quiero que repares en el primer bloque resaltado, que te reproduzco a continuación:
$columnasParaRetorno = array(
$tablasDeBBDD[0].'.nombre',
$tablasDeBBDD[0].'.apellido',
$tablasDeBBDD[2].'.cargo',
$tablasDeBBDD[1].'.ciudad',
$tablasDeBBDD[0].'.fecha_de_ingreso',
$tablasDeBBDD[0].'.salario_bruto_anual'
);
Esto en sí, no es nuevo, ya lo conocemos del artículo anterior. No obstante, te sirve para recordar el orden en que están definidias las columnas de la tabla en la matriz. Siguen el mismo orden que la cabecera de tabla HTML del script principal y, también, el orden en que se recuperará el dataset. Esto es ahora más importante que nunca, ya que las variables sSearch_n
se refieren a las columnas en el orden que están definidas. Así, está claro que sSearch_0
se refiere a $tablasDeBBDD[0].'.nombre'
, sSearch_1
a $tablasDeBBDD[0].'.apellido'
, y, así, sucesivamente.
Lo siguiente que nos llama la atención (y esto si es nuevo, aunque su estructura ya debería sonarte) es la parte que recoge los valores de sSearch_n
y monta una claúsula de consulta basada en el método search()
y lo que se mandó desde el script primario.
/* PREPARAMOS LAS REGLAS DE FILTRADO PARA LAS BUSQUEDAS PROGRAMADAS POR METODO .search()
(BÚSQUEDAS PERSONALIDAS DEL USUARIO). */
$reglasDeBusquedaPorProgramacion = array();
for($i = 0; $i < $numeroDeColumnas; $i++) {
if ($datosDeLlamada['sSearch_'.$i] !== ""){
$reglasDeBusquedaPorProgramacion[] = $columnasParaRetorno[$i].$datosDeLlamada['sSearch_'.$i];
}
}
if (!empty($reglasDeBusquedaPorProgramacion)){
$reglasDeBusquedaPorProgramacion = ' ('.implode(" AND ", $reglasDeBusquedaPorProgramacion).') ';
} else {
$reglasDeBusquedaPorProgramacion = '';
}
Como ves, se comprueban todas las variables sSearch_n
, ya que, aunque aquí hemos montado un formulario relativamente simple, la búsqueda programable podría ser mucho más compleja, implicando a más de una columna. En este caso, con el primer ejemplo (el que busca el apellido York), sólo se va a encontrar en la variable sSearch_1
el valor = 'York'
. Así pues, al terminar esta parte, la variable $reglasDeBusquedaPorProgramacion
tendrá el valor personal.apellido = 'York'
.
Por lo demás, no hay nada nuevo. La nueva claúsula se añade a la consulta en la siguiente línea resaltada:
if ($reglasDeBusquedaPorProgramacion > '') $reglasDeFiltrado[] = $reglasDeBusquedaPorProgramacion;
Así la consulta extrae el dataset adecuado.
CONSIDERACIONES FINALES
Las búsquedas mediante el método search()
son muy potentes. Todo depende del modelado de datos y del diseño del uso que hagamos del método. Sin embargo, hay que tener en cuenta algunos detalles. Por ejemplo. Si usamos una búsqueda por fecha, y usamos este sistema sin más, nunca obtendremos ningún registro. Esto se debe a que las fechas las manejamos, y las escribimos en los campos de texto, en el formato europeo continental, que es dd-mm-aaaa
(o, dd/mm/aa
, o similar). Sin embargo, en la base de datos, las fechas están grabadas como aaaa-mm-dd
. Por lo tanto, en el javascript del script primario tendremos que poner un filtro de modo que, si el campo elegido corresponde a una columna que representa fechas (con esta tabla sería la fecha de ingreso), se tome la fecha tecleada en la caja de texto y se convierta al formato nativo de fechas de la base de datos, antes de crear la claúsula que enviaremos al script secundario. Javascript cuenta con un objeto Date que permite cierto manejo de las fechas y también puedes procesarla como una cadena de texto y separarla en elementos, donde encuentres -
, /
o .
.
Es aconsejable, cuando se usan campos de fecha, no poner un campo de texto libre, sino un datepicker o similar (puedes usar el de bootstrap, el de jQueryUI o cualquiera que prefieras). De esta forma, conseguimos que la fecha se ciña a un formato concreto, sin errores ni ambigüedades, lo que nos facilita su conversión al formato ISO 8601, que es el que emplean las bases de datos.
Hemos modificado el script primario articulo_07.php
, llamándolo articulo_07_b.php
, para que veas lo que podemos hacer para tener esto en cuenta:
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 |
<!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> <!-- El CSS de 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 de Bootstrap --> <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">--> <!-- El CSS de jqueryUI --> <link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> </head> <body> <div class="container"> <div class="row"><br></div> <header> <div class="row"> <div class="col-sm-2"><label for="id_campo">Buscar en campo:</label></div> <div class="col-sm-2"> <select class="form-control input-sm" id="id_campo"> <option value="0" selected>NOMBRE</option> <option value="1">APELLIDO</option> <option value="2">CARGO</option> <option value="3">CIUDAD</option> <option value="4">INGRESO</option> <option value="5">SALARIO</option> </select> </div> <div class="col-sm-2"> <select class="form-control input-sm" id="id_operacion"> <option value="0" selected>Es igual a</option> <option value="1">No es igual a</option> <option value="2">Contiene</option> <option value="3">No contiene</option> <option value="4">Empieza por</option> <option value="5">No empieza por</option> <option value="6">Acaba por</option> <option value="7">No acaba por</option> <option value="8">Es menor que</option> <option value="9">Es menor o igual que</option> <option value="10">Es mayor que</option> <option value="11">Es mayor o igual que</option> </select> </div> <div class="col-sm-2"> <input type="text" class="form-control input-sm" id="valor_a_comparar"> </div> <div class="col-sm-2"> <input type="button" class="btn btn-primary btn-sm" id="boton_buscar" value="Buscar" disabled> </div> <div class="col-sm-2"> <input type="button" class="btn btn-warning btn-sm" id="boton_resetear" value="Resetear búsqueda" disabled> </div> </div> </header> <div class="row"><br></div> <div class="row"> <div class="col-sm-12"> <table id="tabla_de_personal" class="table display table-striped table-bordered"> <thead> <tr> <th>NOMBRE</th> <th>APELLIDO</th> <th>CARGO</th> <th>CIUDAD</th> <th>INGRESO</th> <th>SALARIO</th> </tr> </thead> <tbody> </tbody> </table> </div> </div> </div> <!-- El JavaScript de jQuery --> <script language="javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <!-- El JavaScript de jQuery UI --> <script language="javascript" src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script> <!-- El JavaScript de DataTables --> <script language="javascript" type="text/javascript" src="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.js"></script> <!-- El JavaScript de BootStrap --> <script language="javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <!-- El código JavaScript --> <script language="javascript"> /* La siguiente función recibe una fecha en formato 'dd-mm-yyyy' y la devuelve en el formato ISO 8601 para bases de datos ('yyyy-mm-dd') */ function convertirFecha(fecha){ var datos = fecha.split("-"); var fechaParaBBDD = datos[2] + "-" + datos[1] + "-" + datos[0]; return fechaParaBBDD; } var objetoDataTables_personal = $('#tabla_de_personal').DataTable({ "language": { "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_07.php", "columns" : [ {"data": 0}, {"data": 1}, {"data": 2}, {"data": 3}, {"data": 4}, {"data": 5} ], }); $('label').addClass('form-inline'); $('select, input[type="search"]').addClass('form-control input-sm'); /* Comprobamos si se activa o desactiva el botón de búsqueda personalizada y el de reseteo. */ $('#valor_a_comparar').on('keyup keypress change', function(){ $('#boton_buscar').prop('disabled', ($('#valor_a_comparar').prop('value') == "")); $('#boton_resetear').prop('disabled', ($('#id_campo').prop('value') == "0" && $('#id_operacion').prop('value') == "0" && $('#id_campo').prop('value') == "")); }); $('#id_campo, #id_operacion').on('change', function(){ $('#boton_resetear').prop('disabled', ($('#id_campo').prop('value') == "0" && $('#id_operacion').prop('value') == "0" && $('#valor_a_comparar').prop('value') == "")); }); /* Si se pulsa el botón de reset. */ $('#boton_resetear').on('click', function(){ $('#id_campo, #id_operacion').prop('value', '0'); $('#valor_a_comparar').prop('value', ''); $('#boton_buscar').prop('disabled', true); $('#boton_resetear').prop('disabled', true); objetoDataTables_personal .columns([0,1,2,3,4,5]) .search('') .draw(); }); /* Cuando se pulsa el botón de búsqueda se construye la recla de búsqueda según se ha solicitado. */ $('#boton_buscar').on('click', function(){ var clausula = ""; /* Si el campo es 4, que es una fecha, la que hayamos seleccionado se convierte a formato ISO 8601 para poder ser buscada en la base de datos por el script secundario (se envia, ya en este formato). Si es otro campo, que no contiene una fecha, se envia tal cual se haya tecleado. */ var valorDeComparacion = ($("#id_campo").prop("value") == "4")?convertirFecha($("#valor_a_comparar").prop("value")):$("#valor_a_comparar").prop("value"); switch ($('#id_operacion').prop('value')) { case '0': clausula = " = '" + valorDeComparacion + "' "; // Es igual a lo que hay en el campo de texto break; case '1': clausula = " != '" + valorDeComparacion + "' "; // No es igual a lo que hay en el campo de texto break; case '2': clausula = " LIKE '%" + valorDeComparacion + "%' "; // Contiene lo que hay en el campo de texto break; case '3': clausula = " NOT LIKE '%" + valorDeComparacion + "%' "; // No contiene lo que hay en el campo de texto break; case '4': clausula = " LIKE '" + valorDeComparacion + "%' "; // Empieza por lo que hay en el campo de texto break; case '5': clausula = " NOT LIKE '" + valorDeComparacion + "%' "; // No empieza por lo que hay en el campo de texto break; case '6': clausula = " LIKE '%" + valorDeComparacion + "' "; // Acaba por lo que hay en el campo de texto break; case '7': clausula = " NOT LIKE '%" + valorDeComparacion + "' "; // No acaba por lo que hay en el campo de texto break; case '8': clausula = " < '" + valorDeComparacion + "' "; // Es menor que lo que hay en el campo de texto break; case '9': clausula = " <= '" + valorDeComparacion + "' "; // Es menor o igual que lo que hay en el campo de texto break; case '10': clausula = " > '" + valorDeComparacion + "' "; // Es mayor que lo que hay en el campo de texto break; case '11': clausula = " >= '" + valorDeComparacion + "' "; // Es mayor o igual que lo que hay en el campo de texto break; } objetoDataTables_personal .columns([0,1,2,3,4,5]) .search('') .column($('#id_campo').prop('value')) .search(clausula) .draw(); }); /* Cuando se cambia el campo a buscar, si es una fecha se crea un datepicker, y se bloquea el campo de texto para no poder escribir en directo. Si es otro campo el elegido, se destruye el datepicker y se deja escritura libre. */ $("#id_campo").on("change", function(){ $("#valor_a_comparar").prop("value", ''); if($("#id_campo").prop("value") == "4"){ $("#valor_a_comparar").datepicker({ monthNames: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"], dayNamesMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa"], firstDay: 1, dateFormat: "dd-mm-yy", changeYear: true }); $("#valor_a_comparar").prop("readonly", true); } else { $("#valor_a_comparar").datepicker("destroy"); $("#valor_a_comparar").prop("readonly", false); } }); </script> </body> </html> |
Observa los fragmentos resaltados, dónde hemos incluido comentarios para que puedas seguirlos. Copia en tu localhost esta nueva versión y podrás comprobar su funcionamiento. Observa que, cuando cambiamos el formato de la fecha, lo hacemos internamente, en la variable que luego se enviará al script secundario. En el campo de texto la fecha siempre queda en formato español.
Como siempre, los scripts y la base de datos, en este enlace.
Hola, gracias por tus post. Tengo una duda en lo que ocurre en esta parte del código al modificar el prop. No entiendo bien que hace el segundo argumento.
/* Comprobamos si se activa o desactiva el botón de búsqueda personalizada y el de reseteo. */
$(‘#valor_a_comparar’).on(‘keyup keypress change’, function(){
$(‘#boton_buscar’).prop(‘disabled’, ($(‘#valor_a_comparar’).prop(‘value’) == “”));
$(‘#boton_resetear’).prop(‘disabled’, ($(‘#id_campo’).prop(‘value’) == “0” && $(‘#id_operacion’).prop(‘value’) == “0” &&
$(‘#id_campo’).prop(‘value’) == “”));
});
Ten en cuenta que cuando usas el método
prop()
en jQuery puedes hacerlo de dos formas: con un argumento, para leer el valor de una propiedad, o con dos argumentos, para establecer un valor a la propiedad. Por ejemplovar valor_actual = $('#id_de_control').prop('disabled');
te devolverá untrue
o unfalse
, según sí el elemento id_de_control estádisabled
o no lo está.En cambio, si escribes
$('#id_de_control').prop('disabled', true);
estás forzando a que dicho elemento estédisabled
(deshabilitado).En las líneas que reproduces en tu comentario,
($(‘#valor_a_comparar’).prop(‘value’) == “”)
es una comparación lógica. Siempre devolverá un valortrue
ofalse
. De esta forma, puedes modificar el estado de una propiedad comodisabled
(que siempre debe tener un valor booleano) en base el estado de otro control.Poner en un código
$(‘#boton_buscar’).prop(‘disabled’, ($(‘#valor_a_comparar’).prop(‘value’) == “”));
es lo mismo que poner:if ($(‘#valor_a_comparar’).prop(‘value’) == “”){
$(‘#boton_buscar’).prop(‘disabled’, true);
} else {
$(‘#boton_buscar’).prop(‘disabled’, false);
}
Pero en una sola línea queda más optimizado, menos “barullo” de código y, una vez que se ve la lógica, ya es imposible dejar de verla, con lo que la lectura del código es más cómoda y ágil.
Espero haberte aclarado tus dudas.
Un saludo.
POr Favor:
Como adiciono un objeto al boton de busqueda:
Activas
Para efectuar la consulta Mysql.
Gracias
Hola. No estoy muy seguro de lo que quieres, porque, la verdad, tu consulta es bastante escueta. No sé, realmente, cual es tu duda. Si reformulas tu pregunta de forma más detallada, seguro que alguno podremos ayudarte.
Por ejemplo, que tabla tienes, y que resultados quieres obtener. Ten en cuenta que el trabajo con DataTables siempre se reduce, al final, a dos cosas: el frontend, que muestra una lista de datos y el backend, que proporciona esa lista de datos. Lo demás son sólo añadidos para modificar la consulta en el backend.
Hola. Ya como última duda (es la tercera ahora mismo) tengo esta.
Y si necesitamos encontrar un rango de fechas?
Yo , antes de usar datatables lo hice por programación, con bootstrap hice 2 datepicker, y si había seleccionado algo, ponia lo de between fechainicio and fechafin
Pero como adapto esto a tu código hasta aquí?
Hago lo mismo, pongo 2 datapicker arriba y pongo “filtrar por fechas” y las fechas si se han seleccionado 1 o las 2 (puede ser todas hasta el dia x, o todas desde el día x, sin necesidad de seleccionar las dos)
Y luego como haría para que funcionase? como envío la o las fechas de los datepicker para filtrar y que devuelva los datos entre esas fechas?
Gracias.
Aquí no estoy seguro de haber entendido exactamente tu duda, pero trataré de darte alguna pauta según lo que creo que me pides. Cuando usas en una vista campos de fecha, puedes usar, por ejemplo, los campos tipo date de HTML5. Tienen la ventaja de ser normalizados y, a día de hoy, ya los acepta cualquier navegador. Una de las grandes ventajas que tienen es que te muestran las fechas, visualmente, en el formato adecuado (dd/mm/aaaa), pero, internamente, las mandan en formato ISO 8601, que es el que usa MySQL. En el caso de Datepicker no sé ahora mismo si hace esto así, pero sí he conocido plugins parecidos que no mantenían el formato de fechas.
Una cosa que puedes hacer para pasar las fechas a la consulta (que creo que es lo que quieres) es una solución muy fácil, que yo he empleado en ocasiones (no era con fechas, pero es lo mismo). Cuando defines el objeto DT creas una serie de propiedades. Una de ellas es sAjaxSource, que recibe el nombre del script de destino. A este script, el propio DT le añade sus datos de búsqueda, como sabes. Lo que mucha gente no sabe es que puedes añadirle otros datos “personalizados”. Por ejemplo, podrías poner, como valor,
efectuar_consulta.php?dato=2&otro_dato=45
. DT mandará estos datos, además de los suyos propios. Ya sólo tienes que hacer que, cuando cambies el valor de los campos de fecha se actualice la URL de sAjaxSource para enviar las fechas.Ten en cuenta que si las fechas no van el el formato ISO 8601, a la llegada deberás convertirlas. Además, si falta alguna, quizá debas darle un valor por defecto.