Guía 57 – Lookup eficiente de gran volumen de información – SELECT2

Tengo que reconocer que PHPRunner dispone de una gran variedad de posibilidades de definir campos LOOKUP.

Hay una situación en la que la solución no me satisface por completo y es cuando es necesario buscar en una tabla de muchos registros uno determinado, por ejemplo «clientes» o «empleados» y buscamos por parte del nombre o algún dato adicional. En este caso disponemos de la opción «List page with search» que es eficiente pero que produce un interface que no es habitual en las aplicaciones web y menos si nuestra aplicación está orientada al móvil.

Objetivo

Establecer un campo Lookup en donde permita buscar (mediante AJAX, para no volcar el gran volumen de la tabla en la página). He preseleccionado la alternativa del plugin Jquery SELECT2 con acceso a los datos por Ajax.

DEMO: https://fhumanes.com/select2_ajax/

(1).- Espacio para escribir la información por la que va a buscar. Los criterios de las búsquedas los podemos definir en nuestro código.
(2).- Los valores que van coincidiendo con el criterio. La presentación se puede definir y se puede establecer en 1 línea o varias.
(3).- Es el valor seleccionado.

Solución Técnica

Cómo he indicado, voy a utilizar el plugin SELECT2 que ya he utilizado con otras opciones y que es muy utilizado por los usuarios de los distintos framwork de PHP.

En este caso, lo que deseo es utilizar la funcionalidad del filtrado de los datos utilizando Ajax y eso es lo que he hecho de esta forma.

La integración con PHPRunner la he hecho sin crear plugin PHPRunner, ni nada especial. He definido los campos de la tabla que voy a cargar (en página ADD y EDIT) y además, utilizando la funcionalidad de los «snippet» he definido la estructura de HTML que el plugin de SELECT2 me solicita,

El plugin me requiere 3 partes:

  • La parte de HTML (carga de librería de JavaScript y CSS) y DIV donde se ubica los objetos  del plugin.
  • La parte de JavaScript que describe mediante JQUERY su definición y funcionamiento.
  • La parte de PHP que produce los datos solicitados por AJAX.

1.- La parte de HTML está en fichero «select2.php» y contiene:

<?php
$selected = '';
// Only EDIT
if ($_SESSION['s2_id']) {
  $s2_id = $_SESSION['s2_id'];
  $s2_text = $_SESSION['s2_text'];
  $selected = "<option value='$s2_id' selected='selected'>$s2_text</option>";
}

$html = <<<EOT

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/i18n/es.js"></script>

<div class="s2-input" style='width: 300px;'>
<select class="s2_code form-control" name="Code">
$selected   
</select>
</div>

EOT;

echo $html;

Para las páginas ADD y EDIT, es el mismo HTML, salvo la línea 18, donde en el caso de EDIT se añade la sintaxis de la línea 7, que es el contenido del campo. Las variables globales que tienen los contenidos se crean en el evento «Before Display«.

2.- La parte de JavaScript es la misma para ADD y EDIT. Está en el evento «JavaScript OnLoad event»:

var ctrlCodigoM = Runner.getControl(pageid, 'CodigoMunicipio');
var ctrlCodigoP = Runner.getControl(pageid, 'CodigoProvincia');
var ctrlNombreM = Runner.getControl(pageid, 'NombreMunicipio');
ctrlCodigoM.hide();
ctrlCodigoP.hide();
ctrlNombreM.hide();

// Format Item Lookup
function formatLookup (data_lookup) {
  if (!data_lookup.id) {
    return data_lookup.text;
  }
  var data_lookup = $('<span class="lookup_format">Municipio: '+data_lookup.text+'<BR>Provincia: '+ data_lookup.NomProv + '</span>');
  return data_lookup;
};

// Field SELECT2
var s2_Field = $('.s2_code');  // Import,  simplification

s2_Field.select2({
  ajax: {
    url: 'MyCode/select2_ajax.php',
    dataType: 'json',
    delay: 250,
    data: function (params) {
      var query = {
        search: params.term
      }
      // Query parameters will be ?search=[term]&type=public
      return query;
    },
    processResults: function (data, params) {
      // parse the results into the format expected by Select2
      // since we are using custom formatting functions we do not need to
      // alter the remote JSON data, except to indicate that infinite
      // scrolling can be used
      return {
        results: data
      };
    },
    cache: false
  },
   templateResult: formatLookup,
   language: "es", 
   placeholder: 'Select an option' , 
   allowClear: false
});

// Event CHANGE field by SELECT2
s2_Field.on('change', function (evt) {
  var val = s2_Field.val();
  if ( val != null ) {
    ctrlCodigoM.setValue(val);
    var dataSelected = s2_Field.select2('data');
    // AutoFill
    ctrlCodigoP.setValue(dataSelected[0]['CodProv']);
    ctrlNombreM.setValue(dataSelected[0]['text']);
  } else {  // DELETE value by SELECT2
    ctrlCodigoM.setValue('');
    ctrlCodigoP.setValue('');
     ctrlNombreM.setValue('');
  }
    
});

El código se estructura en 4 partes:

  • Control de los campos adicionales y su ocultación.
  • Función de formateo de la información que va a mostrar para su posible selección.
  • La definición del plugin SELECT2 y sus parámetros.
  • El evento de la selección de un valor (CHANGE) y el «AutoFill» de rellenado de campos de la información seleccionada.

3.- El código PHP para atender a las peticiones de AJAX, fichero «select2_ajax.php».

<?php
@ini_set("display_errors","1");
@ini_set("display_startup_errors","1");
require_once("../include/dbcommon.php"); // Recoger entorno de PHPRuner
$json_arr = array();
if (!$_GET['search']) {
$rs = DB::Query("SELECT m.CodigoMunicipio, m.NombreMunicipio, m.idrp_municipio, m.CodigoProvincia, p.NombreProvincia
FROM rp_municipio m join rp_provincia p on ( m.CodigoProvincia = p.CodigoProvincia) 
order by m.NombreMunicipio 
limit 50");
} else {
    $search = '%'.$_GET['search'].'%';
    $rs = DB::Query("SELECT m.CodigoMunicipio, m.NombreMunicipio, m.idrp_municipio, m.CodigoProvincia, p.NombreProvincia
FROM rp_municipio m join rp_provincia p on ( m.CodigoProvincia = p.CodigoProvincia) WHERE m.NombreMunicipio like '$search' 
order by m.NombreMunicipio 
limit 50");
}
 
while( $data = $rs->fetchAssoc() )
{
   $json_arr[] = ['id'=>$data['CodigoMunicipio'], 'text'=>$data['NombreMunicipio'],'CodProv'=>$data['CodigoProvincia'],'NomProv'=>$data['NombreProvincia']];
}
$json =json_encode($json_arr, JSON_INVALID_UTF8_IGNORE);

echo $json;

Hemos definido el parámetro de «search» para recibir la información de la búsqueda. La primera vez, cuando todavía no se tecleado, el parámetro no llega, por eso hay 2 opciones de query.

Con el contenido del query se construye un array (que puede tener los elementos que se necesite). En el ejemplo, los 2 primeros campos son «id» y «text», siendo la clave y la información que muestra en la selección.

Está claro que todo esto es necesario personalizarlo para cada uno de los casos de nuestros aplicativos, pero creo que queda lo suficientemente simple y fácil, para que aquellos que requieran este tipo de LOOKUP lo pueda implementar partiendo de este ejemplo.

Para cualquier duda o explicación, contactarme a través de mi email [email protected].

Os facilito el código del proyecto para que lo podáis instalar y modificar en vuestros PC’s.

Adjuntos

Archivo Tamaño de archivo Descargas
zip PHPRunner 10.7 + backup de base de datos. 123 KB 162

Blog personal para facilitar soporte gratuito a usuarios de React y PHPRunner