El plugin DataTables (VII). Búsquedas personalizables.

Facebooktwittergoogle_pluslinkedinmailFacebooktwittergoogle_pluslinkedinmail

datatablesEn 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:

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ínea 188: .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ínea 189 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 a columns() 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ínea 190: .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ínea 191: .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ínea 194.

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í:

formulario_york

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í:

form_nueva_york

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:

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:

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.

     

4 comentarios:

  1. 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 ejemplo var valor_actual = $('#id_de_control').prop('disabled'); te devolverá un true o un false, 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 valor true o false. De esta forma, puedes modificar el estado de una propiedad como disabled (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.

  2. 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.

Deja un comentario

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