17 - Autocompletar un control de tipo text


Implementaremos con AJAX el concepto de autocompletar o también conocido como lista de sugerencias. A medida que escribimos caracteres dentro de un control de tipo text mostraremos un conjunto de palabras que comienzan con los caracteres ingresados hasta el momento.

En la realidad los datos se extraen de una base de datos pero para simplificar el problema no lo haremos en este caso.

Veremos los distintos archivos que intervienen para solucionar el problema:

pagina1.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Problema</title>
  <script src="funciones.js"></script>
  <link rel="StyleSheet" href="estilos.css" type="text/css">
</head>
<body>
  <form action="#">
  Ingrese una palabra que comience con a:<br>
  <input type="text" id="palabra" autocomplete="off"><br>
  <div id="resultados"></div>
  <input type="submit" value="buscar">
  </form>
</body>
</html>

Este página no tiene nada nuevo. Es importante notar que hemos dispuesto los elementos para incorporar la hoja de estilo y el archivo donde se encuentran las funciones en JavaScript:

  <script src="funciones.js"></script>
  <link rel="StyleSheet" href="estilos.css" type="text/css">

La hoja de estilo es estilos.css:

#resultados {
  position:absolute;
  background:#ff0;
}

Es importante notar que la clase #resultados hemos definido la propiedad position con el valor absolute. Esto significa que el cuadro donde aparecerá la lista de palabras estará superpuesta a otro contenido de la página. Además el color de fondo es amarillo.

El archivo funciones.js

addEventListener('load',inicializarEventos,false);

function inicializarEventos()
{
  var ob=document.getElementById('palabra');
  ob.addEventListener('keyup',presionTecla,false);
}

var conexion1;
function presionTecla(e)
{
  conexion1=new XMLHttpRequest();
  conexion1.onreadystatechange = procesarEventos;
  palabra=document.getElementById('palabra').value;
  conexion1.open('GET','pagina1.php?palabra='+palabra, true);
  conexion1.send();
}

function procesarEventos()
{
  var resultados = document.getElementById("resultados");
  if(conexion1.readyState == 4)
  {
    if (conexion1.status==200)
    {
      var xml = conexion1.responseXML;
      var pals=xml.getElementsByTagName('palabra');
      resultados.innerHTML='';      
      for(var f=0;f<pals.length;f++)
      {
        resultados.innerHTML = resultados.innerHTML + pals[f].firstChild.nodeValue + '<br>';
      } 
    }
    else
      alert(conexion1.statusText);
  } 
  else 
  {
    resultados.innerHTML = '<img src="../cargando.gif">';
  }
}

Enlazamos la función presionTecla para cuando ocurre el evento keyup del único control text que contiene la página. Es decir que cada vez que el usuario presione una tecla, al momento de soltarla se ejecuta la función presionTecla.

La función presionTecla:

function presionTecla(e)
{
  conexion1=new XMLHttpRequest();
  conexion1.onreadystatechange = procesarEventos;
  palabra=document.getElementById('palabra').value;
  conexion1.open('GET','pagina1.php?palabra='+palabra, true);
  conexion1.send();
}

crea un objeto de la clase XMLHttpRequest, extrae el contenido del text y procede a efectuar la petición al servidor pasando mediante el método GET la cadena ingresada hasta ese momento.

Luego la función procesarEventos:

function procesarEventos()
{
  var resultados = document.getElementById("resultados");
  if(conexion1.readyState == 4)
  {
    if (conexion1.status==200)
    {
      var xml = conexion1.responseXML;
      var pals=xml.getElementsByTagName('palabra');
      resultados.innerHTML='';      
      for(var f=0;f<pals.length;f++)
      {
        resultados.innerHTML = resultados.innerHTML + pals[f].firstChild.nodeValue + '<br>';
      } 
    }
    else
      alert(conexion1.statusText);
  } 
  else 
  {
    resultados.innerHTML = '<img src="../cargando.gif">';
  }
}

Cuando la propiedad readyState informa que llegaron todos los datos y además la propiedad status retorna un 200 procedemos a rescatar los datos mediante la propiedad responseXML.

Por último procedemos a mostrar la lista de palabras dentro del div resultados.

Nos queda el archivo que se ejecuta en el servidor y nos retorna el archivo XML con la lista de palabras (pagina1.php):

<?php
$pal=$_REQUEST['palabra'];
$vec=array('alma','algo','amo','aro','animo','arbol','abrir');
if (strlen($pal)>0)
{
  for($f=0;$f<count($vec);$f++)
  {
    if ($pal==substr($vec[$f],0,strlen($pal)))
      $veciguales[]=$vec[$f];
  }
}
$xml="<?xml version=\"1.0\"?>\n";
$xml.="<palabras>\n";
if (isset($veciguales))
{
  for($f=0;$f<count($veciguales);$f++)
  {
    $xml.="<palabra>".$veciguales[$f]."</palabra>\n";
  }
}
$xml.="</palabras>\n";
header('Content-Type: text/xml');
echo $xml;
?>

Las palabras las tenemos en un vector (en la realidad generalmente se extraen de una base de datos):

$vec=array('alma','algo','amo','aro','animo','arbol','abrir');

Almacenamos en un vector todas las que comienzan con la cadena ingresada hasta el momento:

  for($f=0;$f<count($vec);$f++)
  {
  if ($pal==substr($vec[$f],0,strlen($pal)))
    $veciguales[]=$vec[$f];
  }

Generamos una cadena cuyo contenido es XML:

$xml="<?xml version=\"1.0\"?>\n";
$xml.="<palabras>\n";
if (isset($veciguales))
{
  for($f=0;$f<count($veciguales);$f++)
  {
    $xml.="<palabra>".$veciguales[$f]."</palabra>\n";
  }
}
$xml.="</palabras>\n";

Informamos al navegador que enviaremos un archivo XML:

header('Content-Type: text/xml');

Y por último indicamos la información a enviar:

echo $xml;


Problema resuelto.


Implementar con AJAX el concepto de autocompletar o también conocido como lista de sugerencias. A medida que escribimos caracteres dentro de un control de tipo text mostrar un conjunto de palabras que comienzan con los caracteres ingresados hasta el momento.


pagina1.html



Ejecutar ejemplo



estilos.css




funciones.js




pagina1.php


Problema propuesto.

Modificar el problema resuelto para permitir seleccionar con el mouse entre las palabras propuesta. Hacer que aparezca dentro del control text la que hacemos clic con el mouse.


Ver solución




pagina1.html

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Problema</title> <script src="funciones.js"></script> <link rel="StyleSheet" href="estilos.css" type="text/css"> </head> <body> <form action="#"> Ingrese una palabra que comience con a:<br> <input type="text" id="palabra" autocomplete="off"><br> <div id="resultados"></div> <input type="submit" value="buscar"> </form> </body> </html>

estilos.css

#resultados { position:absolute; background:#ff0; } #menu { font-family: Arial; margin:0px; padding:0px; } #menu ul { margin:0px; padding:0px; list-style-type:none; } #menu a { display: block; padding: 3px; background-color: #f7f8e8; border-bottom: 1px solid #eee; text-align:center; } #menu a:link, #menu a:visited { color: #f00; text-decoration: none; } #menu a:hover { background-color: #369; color: #fff; } #menu a:hover { background-color: #369; color: #fff; }

funciones.js

addEventListener('load',inicializarEventos,false); function inicializarEventos() { var ob=document.getElementById('palabra'); ob.addEventListener('keyup',presionTecla,false); } var conexion1; function presionTecla(e) { conexion1=new XMLHttpRequest(); conexion1.onreadystatechange = procesarEventos; palabra=document.getElementById('palabra').value; conexion1.open('GET','pagina1.php?palabra='+palabra, true); conexion1.send(null); } function procesarEventos() { var resultados = document.getElementById("resultados"); if(conexion1.readyState == 4) { if (conexion1.status==200) { var xml = conexion1.responseXML; var pals=xml.getElementsByTagName('palabra'); cadena='<div id="menu"><ul>'; for(var f=0;f<pals.length;f++) { cadena = cadena + '<li><a>' + pals[f].firstChild.nodeValue + '</a></li>'; } cadena = cadena + '</ul></div>'; resultados.innerHTML = cadena; var obj=document.getElementById("menu"); var lista=obj.getElementsByTagName('a'); for(var f=0;f<lista.length;f++) { lista[f].addEventListener(,'click',seleccionPalabra,false); } } else alert(conexion1.statusText); } else { resultados.innerHTML = '<img src="../cargando.gif">'; } } function seleccionPalabra(e) { var enlace; enlace=e.target; document.getElementById('palabra').value=enlace.firstChild.nodeValue; document.getElementById('menu').style.display='none'; }

pagina1.php

<?php $pal=$_REQUEST['palabra']; $vec=array('alma','algo','amo','aro','animo','arbol','abrir'); if (strlen($pal)>0) { for($f=0;$f<count($vec);$f++) { if ($pal==substr($vec[$f],0,strlen($pal))) $veciguales[]=$vec[$f]; } } $xml="<?xml version=\"1.0\"?>\n"; $xml.="<palabras>\n"; if (isset($veciguales)) { for($f=0;$f<count($veciguales);$f++) { $xml.="<palabra>".$veciguales[$f]."</palabra>\n"; } } $xml.="</palabras>\n"; header('Content-Type: text/xml'); echo $xml; ?>
  Ejecutar ejemplo	

Retornar