Cada día son mayores las facilidades que ofrecen las páginas web para que el usuario se esfuerce lo menos posible. Una de ellas es el autocompletado de las cajas de texto, según se vaya escribiendo te aparece una lista con las posibles opciones o con sugerencias. Es lo que usa Google cuando te va mostrando lo más buscado.
Primero vamos con el diseño, son necesarias tres partes, la caja de texto <INPUT type="text" ...>, una capa que irá debajo de la caja de texto que es la que mostrará las sugerencias y un botón, en este caso una imagen, que servirá para desplegar la lista con todos los valores.
Lo único destacable del diseño es que la lista debe ser una capa con estilo position: absolute y debe ir dentro de otra con estilo position: relative, para que "flote" por encima del texto que se encuentre debajo de la caja de texto.
<input type="text" id="input-fill" autocomplete="off" onkeyup="inputFilling(event, this)" onblur="setInput(this, document.getElementById('lista'))"> <img src="abajo.gif" border="0" onmouseover="cambiarImagen(this, true)" onmouseout="cambiarImagen(this, false)" class="boton" onclick="despliegaFilling(document.getElementById('input-fill'), datos, document.getElementById('lista'))" title="Importar"><div class="contenedor"><div id="lista" class="fill"></div></div>
Si nos fijamos tanto en la caja de texto como en la imagen, veremos que hay varios eventos que debemos tener en cuenta: en la caja de texto cuando se pulsa una tecla muestra la lista con las coincidencias y cuando se pierde el foco se debe escribir en la caja el texto seleccionado de la lista de coincidencias. En la imagen hay que desplegar la lista con todas las posibilidades. Una cosa a tener en cuenta es que la caja de texto debe tener el atributo autocomplete con valor off para que el navegador no actue sobre ella.Las acciones que se deben tener en cuenta son las siguientes:
- Se pulsa una tecla en la caja de texto (usamos el evento onkeyup para no tener problemas con los cursores) y dependiendo de la tecla:
- si la tecla es el cursor hacia la izquierda o hacia la derecha, no hago nada y no dejo que se modifique el texto, volviendo a sobreescribirlo
- si la tecla es el cursor hacia arriba, selecciono el inmediato superior al seleccionado en ese momento en la lista de coincidencias
- si la tecla es el cursor hacia abajo, selecciono el inmediato inferior al seleccionado en ese momento en la lista de coincidencias
- si la tecla es la de retroceso, dejamos que borre el texto seleccionado (hay que tener en cuenta tambien que dentro de la caja habrá una parte del texto que estará seleccionado, que coincidirá con la diferencia de la opción seleccionada y el texto escrito por el usuario)
- si la tecla es la de retorno de carro, deseleccionamos en texto (quedará la opción seleccionado) y eliminamos la lista
- en otro caso, escribimos la letra pulsada
- después de tratar la tecla pulsada, calculamos la lista de opciones y la dibujamos dentro de una tabla
- si pinchamos en una opción de la lista, la escribimos en la caja y ocultamos la lista
La función que trata la pulsación de las teclas y despliega la lista con las coincidencias es la siguiente, la cual recibe dos parámetros, el objeto event y el elemento que contiene la lista:
// Muestra las coincidencias en la lista function inputFilling(evt, obj) { var elems = datos; var fill = document.getElementById('lista'); var tecla = ""; var lista = new Array(); var res = obj.value; var borrar = false; // Almaceno la tecla pulsada if (!IE) { tecla = evt.which; } else { tecla = evt.keyCode; } var texto; // Si la tecla que pulso es una // letra o un espacio, o el intro // o la tecla borrar, almaceno lo // que debo buscar if (!String.fromCharCode(tecla).match(/(\w|\s)/) && tecla != 8 && tecla != 13) { texto = textoAnt; } else { texto = obj.value; } textoAnt = texto; // Si el texto es distinto de vacio // o se pulsa ARRIBA o ABAJO // creo una lista con las palabras // que coinciden con lo que hay // escrito en la caja if ((texto != null && texto != "") || (tecla == 40 || tecla == 38)) { for (var i=0; i<elems.length; i++) { if (elems[i].toUpperCase().indexOf( texto.toUpperCase()) == 0) { lista[lista.length] = elems[i]; } } } // Según la letra que se pulse if (tecla == 37) { // Izquierda // No hago nada } else if (tecla == 38) { // Arriba // Subo la posicion en la // lista desplegable una posición if (posicionListaFilling > 0) { posicionListaFilling--; } // Corrijo la posición del scroll fill.scrollTop = posicionListaFilling*14; } else if (tecla == 39) { // Derecha // No hago nada } else if (tecla == 40) { // Abajo if (obj.value != "") { // Si no es la última palabra // de la lista if (posicionListaFilling < lista.length-1) { // Corrijo el scroll fill.scrollTop = posicionListaFilling*14; // Bajo la posición de la lista posicionListaFilling++; } } } else if (tecla == 8) { // Borrar <- // Se sube la lista del todo posicionListaFilling = 0; // Se permite borrar borrar = true; } else if (tecla == 13) { // Intro // Deseleccionamos el texto if (obj.createTextRange) { var r = obj.createTextRange(); r.moveStart("character", obj.value.length+1); r.moveEnd("character", obj.value.length+1); r.select(); } else if (obj.setSelectionRange) { obj.setSelectionRange( obj.value.length+1, obj.value.length+1); } // Ocultamos la lista fill.style.display = "none"; // Ponemos el puntero de // la lista arriba del todo posicionListaFilling = 0; // Controlamos el scroll fill.scrollTop = 0; return true; } else { // En otro caso que siga // escribiendo posicionListaFilling = 0; fill.scrollTop = 0; } if (lista.length == 0) { // Si la lista es vacia no la mostramos fill.style.display = "none"; } else { // Creamos una tabla con // todos los elementos encontrados fill.style.display = "block"; var html='<table cellspacing="0" '+ 'cellpadding="0" border="0" width="100%">'; for (var i=0; i<lista.length; i++) { html += '<tr id="tr'+obj.id+i+ '" '+(posicionListaFilling == i? ' class="fill" ': '')+ ' onmouseover="seleccionaFilling(\'tr'+ obj.id+'\', '+i+ ')" onmousedown="seleccionaTextoFilling(\'tr'+ obj.id+'\', '+i+')">'; html += '<td>'+lista[i]+'</td></tr>'; } html += '</table>'; } // Escribimos la lista fill.innerHTML = html; // Si no se ha borrado if (!borrar) { if (lista.length != 0) { // Seleccionamos la parte del texto // que corresponde a lo que aparece // en la primera posición de la lista // menos el texto que realmente hemos // escrito obj.value = lista[posicionListaFilling]; if (obj.createTextRange) { var r = obj.createTextRange(); r.moveStart("character", texto.length); r.moveEnd("character", lista[posicionListaFilling].length); r.select(); } else if (obj.setSelectionRange) { obj.setSelectionRange( texto.length, lista[posicionListaFilling].length); } } } return true; }
Una función muy similar es la que se encarga de desplegar la lista cuando se pulsa el botón// Despliega todos los elementos // en la lista function despliegaFilling(obj, elems, fill) { var lista = new Array(); var res = obj.value; var texto=""; // Creamos la lista for (var i=0; i<elems.length; i++) { if (elems[i].toUpperCase().indexOf( texto.toUpperCase()) == 0) { lista[lista.length] = elems[i]; } } textoAnt = ""; if (lista.length == 0) { // Si no hay datos no la mostramos fill.style.display = "none"; } else { // Creamos una tabla // con todos los elementos // de la lista fill.style.display = "block"; var html='<table cellspacing="0" '+ 'cellpadding="0" border="0" '+ 'width="100%">'; for (var i=0; i<lista.length; i++) { html += '<tr id="tr'+obj.id+i+ '" '+(posicionListaFilling == i? ' class="fill" ': '')+ 'onmouseover="seleccionaFilling(\'tr'+obj.id+ '\', '+i+')" onmousedown="seleccionaTextoFilling(\'tr'+ obj.id+'\', '+i+')">'; html += '<td>'+lista[i]+'</td></tr>'; } html += '</table>'; } // Escribimos la lista fill.innerHTML = html; // Seleccionamos el texto if (lista.length != 0) { obj.value = lista[posicionListaFilling]; if (obj.createTextRange) { var r = obj.createTextRange(); r.moveStart("character", texto.length); r.moveEnd("character", lista[posicionListaFilling].length); r.select(); } else if (obj.setSelectionRange) { obj.setSelectionRange( texto.length, lista[posicionListaFilling].length); } } obj.focus(); }
Y por último, necesitaremos otras funciones para ayudar en la funcionalidad// Introduce el texto seleccionado function setInput(obj, fill) { obj.value = textoAnt; fill.style.display = "none"; posicionListaFilling = 0; } // Cambia el estilo de // la palabra seleccionada // de la lista function seleccionaFilling(id, n) { document.getElementById(id + n).className = "fill"; document.getElementById(id + posicionListaFilling).className = ""; posicionListaFilling = n; } // Pasa el texto del filling a la caja function seleccionaTextoFilling (id, n) { textoAnt = document.getElementById(id + n).firstChild.innerHTML; posicionListaFilling = 0; }
Si quieres intentar tú hacer algo parecido, te lo recomiendo, no es complicado, si te aconsejo que vayas introduciendo funcionalidades poco a poco, si no, si que podrá resultar bastante complicado.Puedes bajarte aquí un ejemplo: ARCHIVO
escrito por Luis a las 2/10/2006 08:00:00 p. m.
10 Comentarios:
Muy interesante, pero en Opera no funciona bien. Por lo menos en la 8.5 de Win que estoy usando ahora. Voy a ver en Firefox
Por Anónimo, a las 2/12/2006 10:38:00 a. m.
Hola, gracias por detectarme un fallo, yo lo había probado también con Opera 8.51 y si me funcionaba en local, lo que no detecté es que cuando está metido en el iframe, se mueve todo el documento cuando pulso los cursores para arriba y para abajo, no solo la capa. Que raro, porque uso el scrollTop del DIV y no del document, ¿será que funciona así en Opera?. En Firefox supongo que si funcionará bien, porque yo es el navegador que uso para todo.
Por Anónimo, a las 2/12/2006 11:49:00 a. m.
Hola, pues la verdad es que no había caido en ese error, ahora mismo no sé por qué puede ser, pero le echo un vistazo y te cuento.
Por Anónimo, a las 7/15/2006 02:13:00 p. m.
En esta entrada de Sentido Web, escribí sobre los shortcuts de teclado, puedes usar lo mismo para lo que tu quieres. Tan solo tienes que mirar si el keyCode es el enter y entonces evitas el evento, creo que lo tendrás que hacer en el onkeydown.
Por Anónimo, a las 7/16/2006 03:08:00 p. m.
Hola, ese problema que tienes tú, es algo que me ha pasado a mí muchas veces, hasta que por fín me puse a sacar cómo hacerlo, en el método ini que hay en esta entrada de Sentido Web hago una posible solución, no sé si la más correcta, pero si sé que funciona.
Saludos
Por Anónimo, a las 7/20/2006 08:32:00 a. m.
Hola de nuevo, el tema es que Firefox pasa como parámetro el objeto event por defecto. Si nos creamos una funcion:
function prueba(evt) {
..
}
cuando la llamamos:
prueba();
Firefox realmente lo que hace es hacer esta llamada:
prueba(event);
Pero ten en cuenta que el objeto event como tal no existe, al igual que en IE, por eso en la parte de IE enviamos el objeto event (que cuelga del objeto window) y en Firefox no es necesario pasarselo a la función.
Espero haberme explicado bien.
Saludos
Por Anónimo, a las 7/20/2006 10:55:00 p. m.
Cada vez me haces más difícil responderte... pero eso me gusta, porque así aprendo.
Posible solución, tienes un método en el que creas el objeto, al que llamas desde el onload (por ejemplo)
body onload="ini()"
y luego en este método creas el objeto y le creas el evento onclick
var obj=document.createElement("INPUT");
obj.type="text";
if (window.event) {
obj.onclick = function() { otracosa(event, "valor") };
} else {
obj.onclick = function(evt) { otracosa(evt, "valor") };
}
y luego la funcion a la que se le llama:
function otracosa(evt, txt) {
alert(evt);
alert(txt);
}
Creo que es esto a lo que te refieres, no?
Saludos
document.body.appendChild(kk);
Por Anónimo, a las 7/21/2006 08:07:00 a. m.
Hola.
Me alegro que lo hayas solucionado. Lo siento, pero no he tenido nada de tiempo para solucionar lo del autoselect.
Por Anónimo, a las 7/21/2006 09:59:00 p. m.
HOLA:
tengo un problema con automplete ya que he realizado la modificación para desplegar los datos que extraigo de una base de datos y son almacenados en un archivo con la finalidad que se lea desde ajax para autocompletar en el formulario.
PROBLEMA
ALMACENA LOS REGISTROS DE LA bd EN FORMA HORIZONTAL POR LO CUAL NO PUEDE SER LEIDA
REQUIERO QUE LOS DATOS SE ALMACENEN EN FORMA VERTICAL
¡ALGUIEN SABE HACERLO CON ALGUNA INSTRUCCION EN PHP??
Gracias
Por Anónimo, a las 6/13/2008 08:21:00 p. m.
Gracias, estaba en la búsqueda de esta herramienta autocompletar para mi web.
Por recursos humanos peru, a las 2/27/2010 04:45:00 a. m.
Publicar un comentario
<< Inicio