AUTOCOMPLETAR CON PHP Y XAJAX

Publicado: febrero 4, 2011 en PHP

Crearemos un autocompletar o buscador en línea de personas desde cero con php y mysql, usaremos la librería xajax para llenar y mostrar los datos de forma dinámica desde la base de datos, javascript para controlar algunos eventos, sobre todo para permitir el desplazamiento por la lista de coincidencias del autocompletar.

Primero creamos nuestra tabla Persona:

CREATE TABLE `persona` (
`IdPersona` int(11) NOT NULL auto_increment,
`Nombres` varchar(50) collate utf8_spanish_ci NOT NULL,
`Apellidos` varchar(50) collate utf8_spanish_ci NOT NULL,
`NroDoc` varchar(10) collate utf8_spanish_ci NOT NULL,
PRIMARY KEY  (`IdPersona`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci AUTO_INCREMENT=17 ;

Luego insertamos algunos datos:

INSERT INTO `persona` (`IdPersona`, `Nombres`, `Apellidos`, `NroDoc`) VALUES
(1, 'KARLA', 'KASOS', '2047957052'),
(2, 'ANGELINA', 'JOLIE', '2053134335'),
(3, 'CESAR', 'PISFIL PECHE', '43825485'),
(4, 'GEYNEN', 'MONTENEGRO COCHAS', '12345678'),
(5, 'VARIOS', 'CLIENTE', '-'),
(6, 'JUAQUIN', 'ALVARADO', '33'),
(7, 'VILMA', 'PALMA', '77'),
(8, 'VLADIMIR', 'ZEÑA', '66'),
(9, 'PEDRO', 'PERES PEÑA', '1111111111'),
(10, 'PEÑA', 'PEÑA', '1111111111'),
(11, 'JUAN', 'PERES', '33'),
(12, 'JUANA', 'PERES', '33'),
(13, 'ANDREA', 'TORRES', '33'),
(14, 'MEGAN', 'FOX', '1111111111'),
(15, 'KAREN', 'DEJO', '1111111111'),
(16, 'JUITIJUITI', 'LA', '1111111111');

Estableceremos la conexión a la base de datos usando la extensión del php conocida como PDO (Objeto de datos del php), creamos un archivo con el nombre cado.php.

<!--?php $manejador="mysql"; $servidor="localhost"; $usuario="root"; $pass=""; $base="bdautocompletar"; $cadena="$manejador:host=$servidor;dbname=$base"; $cnx = new PDO($cadena,$usuario,$pass,array(PDO::ATTR_PERSISTENT =--> true));
?>

Ahora crearemos nuestro archivo autocompletar.php, en el manejaremos el xajax (asumo que manejas el xajax), las funciones que me permitirán llamar al xajax, a las funciones del autocompletar y la vista.

Primero diseñamos nuestra vista:


<!--HOJA DE ESTILO Q NORMALMENTE USO PARA DAR FORMATO A MIS TABLAS--></pre>
<div id="divBuscarPersona" style="overflow: auto;">
<fieldset>
<legend><strong>BUSQUEDA PERSONAS:</strong></legend>
<!--CAMPOS OCULTOS PARA EL MANEJO DE LA PAGINACION-->
<input id="pagPersona" type="hidden" name="pagPersona" value="1" />
<input id="TotalRegPersona" type="hidden" name="TotalRegPersona" />
<table>
<tbody>
<tr>
<td>Por:</td>
<td><select name="campoPersona" onchange="javascript:pagPersona.value=1;buscarPersona(event)"><option value="CONCAT(apellidos,' ',nombres)">Apellidos y Nombres</option></select>
<select name="campoPersona" onchange="javascript:pagPersona.value=1;buscarPersona(event)"><option value="NroDoc">Nro Doc.</option></select></td>
</tr>
<tr>
<td>
  <input id="txtIdPersona" type="hidden" />
      Descripción:</td>
<td>
  <input id="frasePersona" style="width: 230px;" onkeyup="javascript:pagPersona.value=1;buscarPersona(event)" onblur="autocompletar_blur('divregistrosPersona')" type="text" name="frasePersona" />
<div id="divregistrosPersona" class="autocompletar" style="display: none;"></div></td>
</tr>
</tbody>
</table>
</fieldset>
</div>
<pre>

Hemos diseñado un buscador de personas con la funcionalidad de enviarle distintos parámetros de búsqueda, pudiendo realizar la búsqueda por Apellidos y Nombres o numero de documento, Quedaría asi:

Ahora cada vez que el usuario seleccione una opción de la lista desplegable o ingrese un texto, se inicializara la búsqueda por la pagina 1 (para ello el código javascript:pagPersona.value=1;), luego llamara a la función buscarPersona (la que mostrara el listado del autocompletar), además cuando el cursor salga de la caja de texto se llamara a la función autocompletar_blur (me permitirá ocultar la lista)

Definimos nuestras funciones de xajax:

<!--?php require('xajax/xajax_core/xajax.inc.php'); $xajax= new xajax(); $xajax--->configure('javascript URI','xajax/');
//$xajax->configure('debug', true);//ver errores

require("datos/cado.php");

function listadopersona($campo,$frase,$pag,$TotalReg){
	Global $ObjPersona;
 	Global $cnx;
	$EncabezadoTabla=array("Apellidos y Nombres","RUC/DNI");
	$regxpag=10;
	$nr1=$TotalReg;
	$inicio=$regxpag*($pag - 1);
	$limite="";
	$frase=utf8_decode($frase);	
	if($inicio==0){		
		$rs = $cnx->query("SELECT Distinct persona.idpersona, CONCAT(apellidos,' ',nombres) as Nombres, NroDoc FROM persona WHERE ".$campo." LIKE '%" . $frase . "%' ". $limite);	
    	$nr1=$rs->rowCount();
	}
	$nunPag=ceil($nr1/$regxpag);
	$limite=" limit $inicio,$regxpag";
	$rs = $cnx->query("SELECT Distinct persona.idpersona, CONCAT(apellidos,' ',nombres) as Nombres, NroDoc FROM persona WHERE ".$campo." LIKE '%" . $frase . "%' ". $limite);	
    $nr=$rs->rowCount()*($pag);	
	$CantCampos=$rs->columnCount();
    $cadena="Encontrados: $nr de $nr1";
    $registros="
	<table id='tablaPersona' class=registros>
    <tr>";
	for($i=0;$i<count($EncabezadoTabla);$i++){
	$registros.="<th>".$EncabezadoTabla[$i]."</th>";
	}
	$cont=0;
    while($reg=$rs->fetch()){
	   $cont++;
	   if($cont%2) $estilo="par";
	   else $estilo="impar";
	   $registros.= "<tr id='".$reg[0]."' class='$estilo' onClick='mostrarPersona(".$reg[0].")'>";
	   for($i=0;$i<$CantCampos;$i++){
		   if($i<>0){
			   //LO SGTE PARA OBTENER LA PORSION DE TEXTO QUE COINCIDE Y CAMBIARLE DE ESTILO, $cadena2 -> está variable contiene el valor q coincide, al cual lo ubico en una etiqueta span para cambiarle de estilo.
				$posicion  = stripos($reg[$i], $frase);
				if($posicion>-1){
					$cadena1 = substr($reg[$i], 0, $posicion);
					$cadena2 = substr($reg[$i], $posicion, strlen($frase));
					$cadena3 = substr($reg[$i], ($posicion + strlen($frase)));

					$dato = $cadena1.'<span>'.$cadena2.'</span>'.$cadena3;
					$registros.= "<td>".$dato."</td>";
				}else{
					$registros.= "<td>".$reg[$i]."</td>";
					}
		   }
	   }
	   $registros.=$RegistroSeleccion;
	   $registros.= "</tr>";
    }
	//PAGINACION
	$registros.="</table>".$cadena."<center>Pag: ";
	for($i=1;$i<=$nunPag;$i++){
		$registros.='<a href="#" onClick="javascript:pagPersona.value='.$i.';buscarPersona(event)">'.$i.' </a>';
	}
	$registros.='</center>';

	$registros=utf8_encode($registros);
	$objResp=new xajaxResponse();
	$objResp->assign('divregistrosPersona','innerHTML',$registros);
	$objResp->assign('TotalRegPersona','value',$nr1);
	return $objResp;
}

function mostrarPersona($id){
  Global $ObjPersona;
  Global $cnx;
  $sql = "SELECT IdPersona,CONCAT(apellidos,' ',nombres) as Nombres, NroDoc FROM Persona WHERE 1=1";
  $sql .= " AND IdPersona=".$id;
  $rs = $cnx->query($sql);
  $reg= $rs->fetchObject();
  $objResp=new xajaxResponse();
  $objResp->assign('txtIdPersona','value',$reg->IdPersona);
  $objResp->assign('frasePersona','value',utf8_encode($reg->Nombres));
  return $objResp;

}
$xajax->registerFunction('mostrarPersona');
$flistadopersona = & $xajax-> registerFunction('listadopersona');
$flistadopersona->setParameter(0,XAJAX_INPUT_VALUE,'campoPersona');
$flistadopersona->setParameter(1,XAJAX_INPUT_VALUE,'frasePersona');
$flistadopersona->setParameter(2,XAJAX_INPUT_VALUE,'pagPersona');
$flistadopersona->setParameter(3,XAJAX_INPUT_VALUE,'TotalRegPersona');

$xajax->processRequest();
echo"<!--?xml version='1.0' encoding='UTF-8'?-->";
?>

Que la función listadoPersona no te asuste, es una función que yo uso normalmente para generar listados con paginación, es solo cuestión de enviarle la consulta adecuada a tu base de datos y la función se encargara de hacer todo el trabajo (puedes usar tu función para listar tus datos o ver un ejemplo del autocompletar sin paginación aqui), lo que si debes entender es que los datos que se obtienen de la bd son mostrados por la función listadoPesona mediante una tabla, es importante ponerle un id a esa tabla, para luego programar la forma de navegación a través de sus filas:

<table id=’tablaPersona’>

Lo siguiente que debes realizar es asignarle un id a cada fila de tu tabla (esto me permitirá navegar con las teclas de dirección) y decirle que llame a la función mostrarPersona cada vez que se haga clic en cualquier parte de la fila:

$registros.= “<tr id=’”.$reg[0].”‘ class=’$estilo’ onClick=’mostrarPersona(“.$reg[0].”)’>”;

Otra cosa de especial de esta función es que por cada frase ingresada se buscara en la bd y la frase que va coincidiendo la iremos cambiando de color:

Ejemplo:

//$reg[$i] -> Contiene el valor del campo en la columna $i
//$frase    -> Es el texto que se va ingresando en la caja de texto.

//$reg[$i]=MONTENEGRO
//$frase=TEN

//Obtenemos la posicion donde conicide la frase, la posición seria igual a 4
$posicion  = stripos($reg[$i], $frase);
//Obtengo una cadena con la primera parte que no coincidió, seria igual a MON
$cadena1 = substr($reg[$i], 0, $posicion);
//Obtengo la cadena que coincide, seria igual a TEN, auque podrías asignar directo el valor de la variable frase, pero podría q en tu bd este en minúsculas.
$cadena2 = substr($reg[$i], $posicion, strlen($frase));
//Obtengo una cadena con la ultima parte que no coincidió, seria igual a EGRO
$cadena3 = substr($reg[$i], ($posicion + strlen($frase)));

//Ahora uno las tres cadenas obtenidas, y el valor de la cadena que coincide lo pongo dentro de una etiqueta  (a la cual le aplicare una css para diferenciarlo)
$dato = $cadena1.''.$cadena2.''.$cadena3;
$registros.= "".$dato."
";

Lo que quedaría MON<span>TEN</span>EGRO, visualmente MONTENEGRO.

También registramos con el xajax a la función mostraPersona, la cual la usaremos cada vez que el usuario de clic en una fila de la tabla, para pasar los datos de la persona seleccionada a la caja de texto donde se escribe (podríamos haberlo hecho directamente con javascript pero uso el xajax, suponiendo que necesites mostrar otros datos de la persona en otras cajas)

Ahora definiremos las funciones de javascript que me permitirán llamar a las funciones del xajax y las del autocompletar (que las veremos más adelante)

<script type="text/javascript">// <![CDATA[
LAS SIGUIENTES FUNCIONES LAS USO PARA LLAMAR AL XAJAX Y A LAS FUNCIONES DEL AUTOCOMPLETAR-->
function buscarPersona(e){
  if(!e) e = window.event;
    var keyc = e.keyCode || e.which;

    if(keyc == 38 || keyc == 40 || keyc == 13) {
        autocompletar_teclado('divregistrosPersona', 'tablaPersona', keyc);

    }else{
	  	<?php $flistadopersona->printScript() ?>;
  		divregistrosPersona.style.display="";
		window.setTimeout('divregistrosPersona.style.display="";', 300);
  }
}
function mostrarPersona(id){
   xajax_mostrarPersona(id);
   divregistrosPersona.style.display="none";
}
// ]]></script>

Emtonces cada vez que el usuario digite una frase en la caja de texto, se ejecutara la función anterior buscarPersona, la cual evalúa el evento que la desencadeno, si el usuario presiona las teclas flecha abajo, flecha arriba o enter, se llamara a la función autocompletar_teclado (la cual nos permitirá navegar por la lista), si el usuario presiono cualquier otra tecla se mostrara el listado generado por el xajxa y se visualizara el div, ya que inicialmente lo hemos ocultado (he si usamos un div flotante).

Para el caso cuando el usuario de clic en el número de página 2 (suponiendo que hay más de una), al dar clic en este link, se perdería el foco de la caja de texto frasePersona, y se desencadenara el evento onblur, el cual tiene programado una función para ocultar la lista (div) en un determinado tiempo, para evitar que la lista se oculte al momento de dar clic en el link de paginación, la vuelvo a abrir inmediatamente después de que la otra función la oculta con la siguiente línea:

window.setTimeout(‘divregistrosPersona.style.display=””;’, 300);

Ahora creamos el archivo autocompletar.js el cual tu puedes reutilizar en tus sitios web, solo tienes que enviarle los parámetros correctos.

//FUNCION QUE ME PERMITE OCULTAR LA LISTA AL PERDER EL FOCO DE  LA CAJA
function autocompletar_blur(div) {
    window.setTimeout('autocompletar_blur2(\'' + div + '\')', 300);
}

function autocompletar_blur2(div) {
  document.getElementById(div).style.display="none";
}
/*FUNCION PARA NAVEGAR POR LA LISTA, es importante que envíes el id del div del listado y de la tabla, no olvides que cada fila tr debe tener un id también.*/
function autocompletar_teclado(div, tabladiv, keyc) {
    var child = document.getElementById(tabladiv).rows;
    var indice = -1;

    for(var i=0; i < child.length; i++) {
        if(child[i].className == 'tr_hover') {
            indice = i;
        }
        if(i % 2==0){
	        child[i].className = 'impar';
		}else{
			child[i].className = 'par';}
    }

    // return
    if(keyc == 13) {
        var seleccionado = '';

        if(child[indice].id) {
            seleccionado = child[indice].id;
        } else {
            seleccionado = child[indice].id;
        }

        mostrarPersona(seleccionado);

    } else {
        // abajo
        if(keyc == 40) {
            if(indice == (child.length - 1)) {
                indice = 1;
            } else {
				if(indice==-1) indice=0;
                indice++;
            }

        // arriba
        } else if(keyc == 38) {
            indice--;
            if(indice==0) indice=-1;
            if(indice < 0) {
                indice = (child.length - 1);
            }
        }

        child[indice].className = 'tr_hover';
    }
}

Referenciamos en nuestro archivo autocompletar.php al archivo autocompletar.js

<!--FUNCIONES AUTOCOMPLETAR: LAS CUALES PODEMOS REUTILIZAR EN DISTINTOS ARCHIVOS-->
<script type="text/javascript" src="autocompletar.js"></script>

Hasta ahora ya hemos podido, llenar el listado de personas con el xajax, mostralo y navegarlo  mediante javascript, pero para poder visualizar la funcionalidad de navegación es necesario usar hojas de estilo.

<!--AUTOCOMPLETAR: LOS ESTILOS SIGUIENTES SON PARA CAMBIAR EL EFECTO AL MOMENTO DE NAVEGAR POR LA LISTA DEL AUTOCOMPLETAR-->

<!--AUTOCOMPLETAR-->

Lo anterior nos permite cambiar de estilo cada vez que el usuario desplace el puntero del mouse por las filas del listado o cuando el usuario se desplace con las flechas arriba o abajo, además que le damos un fondo solido para evitar que los datos se confundan si es que tuviéramos más información en la página.

Tú puedes usar tus hojas de estilo que usas para aplicar estilo a tus tablas, lo único que tendrías que cambiar seria el color de selección (lo cual está en el fragmento de código de estilos líneas arriba vistos), quedaría así:

Espero te haya sido de ayuda, estoy seguro que te dará algunas ideas para hacer tu propio autocompletar, los dejo el documento del ejemplo en formato .pdf

Descarga documento desde aquí: Autocompletar con php y xjax.pdf

Descarga el código fuente desde aquí: https://github.com/geynen/autocomplete-php-xajax

BIBLIOGRAFIA

About these ads
comentarios
  1. Alexis dice:

    Hermano! muchas gracias por tu aporte he aprendido mucho esta vez

    saludos

  2. markitos dice:

    hola amigo me da mucho gusto que existan personas como tu que se encargen de repartir conocimiento veras quisiera ver si pudieras ayudarme de la siguiente manera, estoy trabajando un sistema web con xajax y pues necesito ayuda para poder recargar mi contenido web pero solo una parte como se hace en ajax o js me seria de mucha ayuda si puedieras darme una pista de como hacerlo, tambien quisiera sabr como hacer para poder limpiar las cajas de texto despues de insertar un registro. de antemano te doy las gracias y pues tu blog es una chulada

    • Geynen dice:

      Hola Markos, gracias por el el comentario, bueno vamos por la pregunta que se te puede responder mas rapido:
      Como limpiar las cajas de texto, puedes usar lo siguiente con javascript:
      document.getElementById(“nombrecaja”).value=””;
      nombrecaja.value=””; o tb
      nombreform.nombrecaja.value=””

      o con el mismo xajax:
      $objResp=new xajaxResponse();
      $objResp->assign(‘divnombre’,’innerHTML’,””);
      o $objResp->assign(‘NombreCaja’,’value’,””);

  3. markitos dice:

    graciaas amigo por lo de limpiar las cajas si me funciono

  4. markitos dice:

    amigo tendras idea de por que el codigo de autocompletar y el que me mandaste ayer no funcionan en firefox

  5. guti dice:

    BUEN DIA CABALLERO , TENGO UN PROBLEMA CON LA CONEXIÓN NO DEVUELVE DATOS Y CUANDO NO INCLUYO DATOS/CADO.PHP NO SALE EL AUTOCOMPLETAR PERO CUANDO NO LO INCLUYE ME SALE VACIA CUAL SERIA EL PROBLEMA

  6. markitos dice:

    si amigo eso es cierto he notado que muchas cosas que ejecutas en xajax no las hace y algunas si pero pues quien sabe cual sera el problema

  7. Veris dice:

    Hola… ayudame. porque no funciona en firefox y si en el internet explorer.. ?? que le falta al firefox para que esto funcione….
    te agradeceria mucho si puedes ayudarme..

    • Geynen dice:

      Hola!!! Busca la linea del DOCTYPE y reemplazala por esto:

      <?php
      echo $_SERVER['REMOTE_ADDR'].'<br>';
      echo $_SERVER['HTTP_USER_AGENT'];
      if(strstr($_SERVER['HTTP_USER_AGENT'],'IE')){
      ?>
      //aca va la linea del DOCTYPE
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "XXXX://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <?php
      }
      ?>
      

      No puedo pegar la linea del doctype aca en el comentario me genera error. cambiar XXXX por http

      • Veris dice:

        Muchisimas gracias.. por tu tiempo y tu ayuda.. me diste un gran ejemplo.. al invertir tu tiempo en ayudar los demas que aun somos novatitos en esto.. DTB

  8. Ricardo dice:

    Hola Geynen esta muy chevere tu spacio… soy Cordova del proyecto pisfil sabes estoy buscando alguna libreria en ajax que me permita crear busquedas de personas pero al estilo de tu bandeja de entrada del hotmail algo asi cuando buscas uno de tu lista de correo… bueno si si encuentras algo parecido seria chevere … nos vemos Dios te bendiga

    • Geynen dice:

      Ricardo, mi estimado, no necesitas más que xajax o cualquier libreria q te permita hacer ajax, si lees con detenimiento este post…pz lo que pides es lo que se está logrando…bueno gracias por tu comentario, cdt.

  9. Ricardo dice:

    jajaja si ya me di cuenta… pense que era la forma antigua de busquedas que habias creado para pisfil… esta bien chevere voy a descargarme los scripts … muchas gracias te pasaste ah nos vemos suerte en todo

  10. vladi dice:

    Gracias por compartir, espero que sea de mucha ayuda

  11. carlos dice:

    Geynen, ¿Por qué no me aparece los resultados de “Encontrados 0 de 0″ y “Pag.”, aún cuando me lista los registros coincidentes?, gracias por tu atención.

    • Geynen dice:

      hola carlos, disculpa la demora.

      si te muestra resultados, pero no te indica la cantidad de registros encontrados podria ser porque en tu caja de texto no lo envias el valor 1, ya que en el codigo se necesita para hacer calculos de paginación:

      espero se este tu problema.

  12. Fernando rueda dice:

    Buenas tardes Geynen

    Descargue su post, y le he esatdo probando, solo que realice unos cambios primero, pues yo trabajo con postgres y mi aplicacion ya esta bastande abanzada, yo ya he realizado auntoconpletar antes, pero me llamo mucho la atencion este codigo, quisas por el modelo de orientacion que tiene y se ve bastante seguro, pero me esta presentando el siguiente error :

    Wed Mar 14 16:14:09 EST 2012
    ERROR: No response processor is available to process the response from the server.Content-Type: text/html.Check for error messages from the server.Wed Mar 14 16:14:09 EST 2012
    RECEIVED [status: 200, size: 159 bytes, time: 110ms]:Fatal error: Call to a member function rowCount() on a non-object in D:\wamp\www\autocompletar\autocompletar.php on line 29

    He tratado de hacer cambios pero no veo que cancione, me podria dar una mano, depronto estoy omitiendo alguna bobada pero no se …. por ejemplo se que CONCAT en postgres no existe pero igual solo quiero mostrar el nombre y la cedula del usuario.

    Muchas gracias por la atencion prestada.

    • Geynen dice:

      Buen día Fernando, al parecer tu problema es en tu consulta al momento de gestionar la data a tu servidor.

      ERROR: No response processor is available to process the response from the server.

      te sugiero revises bien la consulta o copies el fracmento de codigo donde haces la consulta, kisas te pueda ayudar mejor.

  13. dario dice:

    buen dia Geynen, como hago para que la persona que selecciono se me valla a una caja de texto

  14. Xavi Aioria dice:

    Muchas gracias funciona a la perfeccion, ahora lo estoy cambiando a para que funcione con Oracle.

  15. jesus dice:

    Buen dia Geynen tu ejemplo lo vi y re resulto muy interesante y gracias por compartirlo, tengo una consulta espero que me ayudes, como puedo hacer para pasar el resultado de la lista en dos campos de texto cuando selecciono con la tecla 13, osea mostrarlo por campos cuando selecciono y apreto enter.

    • Geynen dice:

      Jesus, gracias por el comentario… este es un artículo que escribi hace mucho tiempo!! Trataré de responder, si te fijas en el html, yo tengo una caja oculta en el cual guardo el id de la persona (es decir estoy guardando los datos de la persona seleccionada en 2 cajas de texto)… debes fijarte que en el xjax asigno los datos a ambas cajas.

      Espero aclarar tu duda… saludos!!

Deja un comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s