Necesitaremos los siguientes elementos:
- Base de datos: Usaremos MySQL como SMBD y, para este ejemplo tendremos una tabla cargada con un listado de ciudades
- Un script PHP que capture los datos de la base de datos según el parámetro enviado.
- Una Página Receptora de los resultados, en la que colocaremos la zona para mostrarlos. Además esta misma enviará la solicitud de los datos que necesita mostrar.
Nombre
Id
Documento
Paso 1. Empezamos construyendo la página donde se desencadenan todos los eventos. En nuestro ejemplo usaremos lo siguiente:
<html>
<head>
<title>Menu desplegable con AJAX</title>
</head>
<body>
<div style="float:left;width:80px;">Nombre</div>
<div style="float:left; width:220px;">
<input type="text" style="width:200px;" name="nom" id="nom" value="" />
</div>
<div style="float:left; width:130px;">
Id <input type="text" style="width:90px;" name="id" id="id" value="" />
</div>
<div style="float:left; width:190px;">
Documento <input type="text" style="width:90px;" name="cid" id="cid" value="" />
</div>
</body>
</html>
<head>
<title>Menu desplegable con AJAX</title>
</head>
<body>
<div style="float:left;width:80px;">Nombre</div>
<div style="float:left; width:220px;">
<input type="text" style="width:200px;" name="nom" id="nom" value="" />
</div>
<div style="float:left; width:130px;">
Id <input type="text" style="width:90px;" name="id" id="id" value="" />
</div>
<div style="float:left; width:190px;">
Documento <input type="text" style="width:90px;" name="cid" id="cid" value="" />
</div>
</body>
</html>
Paso 2. Desarrollamos los elementos básicos para que AJAX funcione. Primero la función para crear instancias del objeto XMLHTTPRequest. En el post AJAX para principiantes - 2 encontraremos mas detalles acerca de este tema.
function nuevoAjax(){
var ajax;
if (window.XMLHttpRequest) { // codigo para IE7+, Firefox, Chrome, Opera, Safari
ajax=new XMLHttpRequest();
} else { // codigo para IE6, IE5
ajax=new ActiveXObject("Microsoft.XMLHTTP");
}
return ajax;
}
var ajax;
if (window.XMLHttpRequest) { // codigo para IE7+, Firefox, Chrome, Opera, Safari
ajax=new XMLHttpRequest();
} else { // codigo para IE6, IE5
ajax=new ActiveXObject("Microsoft.XMLHTTP");
}
return ajax;
}
Paso 3. Crearemos el archivo php que se conectará a la base de datos para sacar de ella lo que necesitamos. A este archivo lo llamaremos array_listado.php, luego lo veremos mencionado en el proceso de captura de datos con Ajax en el paso 4.
<?php
$hostname = "localhost";
$database = "my_database";
$username = "my_username";
$password = "my_password";
$conexion = mysql_pconnect($hostname, $username, $password) or trigger_error(mysql_error(), E_USER_ERROR);
mysql_select_db($database, $conexion);
$sql_query = "SELECT * FROM clientes";
$cliData = mysql_query($sql_query, $conexion) or die(mysql_error());
$cliCount = mysql_num_rows($cliData);
if ($cliCount>0) {
$cli = mysql_fetch_assoc($cliData);
$k = 0;
do {
echo $cli['id']."~".$cli['cli_nombre']."~".$cli['cli_cid']."--\n";
} while ($cli = mysql_fetch_assoc($cliData));
}
?>
$hostname = "localhost";
$database = "my_database";
$username = "my_username";
$password = "my_password";
$conexion = mysql_pconnect($hostname, $username, $password) or trigger_error(mysql_error(), E_USER_ERROR);
mysql_select_db($database, $conexion);
$sql_query = "SELECT * FROM clientes";
$cliData = mysql_query($sql_query, $conexion) or die(mysql_error());
$cliCount = mysql_num_rows($cliData);
if ($cliCount>0) {
$cli = mysql_fetch_assoc($cliData);
$k = 0;
do {
echo $cli['id']."~".$cli['cli_nombre']."~".$cli['cli_cid']."--\n";
} while ($cli = mysql_fetch_assoc($cliData));
}
?>
Paso 4. Ahora crearemos una función con la que cargaremos en nuestra página un listado de nombre, id y documentos (para nuestro ejemplo).
var listado = new Array();
function cargar_array_listado() {
var ajaxL = nuevoAjax();
ajaxL.open("GET", "array_listado.php", true);
ajaxL.onreadystatechange=function() {
if (ajaxL.readyState==4) {
var tabla = ajaxL.responseText;
var registros = tabla.split("--");
for (var u in registro) {
datos = registro[u].split("~");
listado[u]= new Object();
listado[u]['id']=datos[0];
listado[u]['nom']=datos[1];
listado[u]['cid']=datos[2];
}
}
}
ajaxL.send(null);
}
Podemos darnos cuenta de que:function cargar_array_listado() {
var ajaxL = nuevoAjax();
ajaxL.open("GET", "array_listado.php", true);
ajaxL.onreadystatechange=function() {
if (ajaxL.readyState==4) {
var tabla = ajaxL.responseText;
var registros = tabla.split("--");
for (var u in registro) {
datos = registro[u].split("~");
listado[u]= new Object();
listado[u]['id']=datos[0];
listado[u]['nom']=datos[1];
listado[u]['cid']=datos[2];
}
}
}
ajaxL.send(null);
}
- A través de la función open del objeto Ajax, ejecutamos en el servidor el archivo array_listado.php.
- Usando el método responseText del objeto Ajax, capturamos la respuesta del servidor como texto plano. Este contenido será una serie de registros separados por el doble guion "--", donde cada dato estará separado por el símbolo "~". Obviamente podemos usar el método responseXML, para lo cual deberíamos haber configurado nuestra respuesta del archivo array_listado.php como datos en formato XML.
- Considerando que tenemos una respuesta en formato de texto plano, hacemos uso de la función split de JavaScript para obtener cada dato y construir la matriz de datos que necesitamos.
Paso 5. Agregaremos algunas funciones que nos ayudarán a que nuestra escritura en el campo de texto de como resultado que se despliegue un listado con los nombres que coincidan en cualquier parte con nuestra escritura.
function teclear(evt,campo){
if (campo.value.length == 0) {
if ((evt.keyCode == 9)||(evt.keyCode == 13)) {
clear();
}
} else if ((campo.value.length > 0)&&(campo.value.length < 3)) {
document.getElementById('selector').innerHTML = "";
if ((evt.keyCode == 9)||(evt.keyCode == 13)) { // tab o enter
clear();
}
} else {
if ((evt.keyCode > 47)&&(evt.keyCode < 91)){ // cualquier letra o numero
autoCompletar(campo);
}
if ((evt.keyCode == 37)||(evt.keyCode == 38)) { // flecha hacia arriba o hacia atras
if (document.getElementById('sel').selectedIndex > 0) {
document.getElementById('sel').selectedIndex = (document.getElementById('sel').selectedIndex)-1;
campo.value = document.getElementById('sel').options[document.getElementById('sel').selectedIndex].text
}
}
if ((evt.keyCode == 39)||(evt.keyCode == 40)) { // flecha hacia abajo o hacia delante
if (document.getElementById('sel').selectedIndex < (document.getElementById('sel').length-1)) {
document.getElementById('sel').selectedIndex = (document.getElementById('sel').selectedIndex)+1;
campo.value = document.getElementById('sel').options[document.getElementById('sel').selectedIndex].text
}
}
if ((evt.keyCode == 9)||(evt.keyCode == 13)) { // tab o enter
if (document.getElementById('sel').selectedIndex != -1) {
var idsel = document.getElementById('sel').options[document.getElementById('sel').selectedIndex].value;
document.getElementById('id').value = idsel;
look(idsel);
document.getElementById('selector').innerHTML = "";
document.getElementById('cid').focus();
} else {
document.getElementById('selector').innerHTML = "";
clear();
}
}
}
return false;
}
function autoCompletar(field) {
// crear selector
var lista = "";
var cuent = 0;
var ubica = 0;
var selecto = "";
for (var k=0; k < listado.length; k++) {
ubica = listado[k].name.toUpperCase().indexOf(field.value.toUpperCase());
if ((ubica == 0)||(listado[k].name.toUpperCase().charCodeAt(ubica-1)==32)) {
selecto += "<option value='" + listado[k].code + "' >" + listado[k].name + "</option>\n";
cuent++;
}
}
lista = "<select style=\"width:200px;\" name=\"sel\" id=\"sel\" onfocus = \"document.getElementById('nom').focus()\" onclick = \"document.getElementById('nom').value = this.options[this.selectedIndex].text\">\n" + selecto + "</select>\n";
// mostrar selector
if (cuent == 0) {
document.getElementById('selector').innerHTML = "";
document.getElementById('re_id').value = 0;
} else {
document.getElementById('selector').innerHTML = lista;
document.getElementById('sel').setAttribute('size',cuent+1);
document.getElementById('sel').selectedIndex = -1;
}
}
function clear() {
document.getElementById('id').value = 0;
document.getElementById('cid').value = '';
document.getElementById('nom').value = '';
document.getElementById('nom').focus();
}
function look(id) {
for (var k=0; k<listado.length; k++) {
if (listado[k].code == id){
document.getElementById('cid').value = listado[k].cid;
document.getElementById('nom').value = listado[k].name;
}
}
}
if (campo.value.length == 0) {
if ((evt.keyCode == 9)||(evt.keyCode == 13)) {
clear();
}
} else if ((campo.value.length > 0)&&(campo.value.length < 3)) {
document.getElementById('selector').innerHTML = "";
if ((evt.keyCode == 9)||(evt.keyCode == 13)) { // tab o enter
clear();
}
} else {
if ((evt.keyCode > 47)&&(evt.keyCode < 91)){ // cualquier letra o numero
autoCompletar(campo);
}
if ((evt.keyCode == 37)||(evt.keyCode == 38)) { // flecha hacia arriba o hacia atras
if (document.getElementById('sel').selectedIndex > 0) {
document.getElementById('sel').selectedIndex = (document.getElementById('sel').selectedIndex)-1;
campo.value = document.getElementById('sel').options[document.getElementById('sel').selectedIndex].text
}
}
if ((evt.keyCode == 39)||(evt.keyCode == 40)) { // flecha hacia abajo o hacia delante
if (document.getElementById('sel').selectedIndex < (document.getElementById('sel').length-1)) {
document.getElementById('sel').selectedIndex = (document.getElementById('sel').selectedIndex)+1;
campo.value = document.getElementById('sel').options[document.getElementById('sel').selectedIndex].text
}
}
if ((evt.keyCode == 9)||(evt.keyCode == 13)) { // tab o enter
if (document.getElementById('sel').selectedIndex != -1) {
var idsel = document.getElementById('sel').options[document.getElementById('sel').selectedIndex].value;
document.getElementById('id').value = idsel;
look(idsel);
document.getElementById('selector').innerHTML = "";
document.getElementById('cid').focus();
} else {
document.getElementById('selector').innerHTML = "";
clear();
}
}
}
return false;
}
function autoCompletar(field) {
// crear selector
var lista = "";
var cuent = 0;
var ubica = 0;
var selecto = "";
for (var k=0; k < listado.length; k++) {
ubica = listado[k].name.toUpperCase().indexOf(field.value.toUpperCase());
if ((ubica == 0)||(listado[k].name.toUpperCase().charCodeAt(ubica-1)==32)) {
selecto += "<option value='" + listado[k].code + "' >" + listado[k].name + "</option>\n";
cuent++;
}
}
lista = "<select style=\"width:200px;\" name=\"sel\" id=\"sel\" onfocus = \"document.getElementById('nom').focus()\" onclick = \"document.getElementById('nom').value = this.options[this.selectedIndex].text\">\n" + selecto + "</select>\n";
// mostrar selector
if (cuent == 0) {
document.getElementById('selector').innerHTML = "";
document.getElementById('re_id').value = 0;
} else {
document.getElementById('selector').innerHTML = lista;
document.getElementById('sel').setAttribute('size',cuent+1);
document.getElementById('sel').selectedIndex = -1;
}
}
function clear() {
document.getElementById('id').value = 0;
document.getElementById('cid').value = '';
document.getElementById('nom').value = '';
document.getElementById('nom').focus();
}
function look(id) {
for (var k=0; k<listado.length; k++) {
if (listado[k].code == id){
document.getElementById('cid').value = listado[k].cid;
document.getElementById('nom').value = listado[k].name;
}
}
}
Paso 6. Finalmente, agregamos un par de detalles al campo de texto nombre, para que se desencadenen las funciones programadas para los eventos onFocus y onKeyUp
<input id="nom" name="nom" onfocus="cargar_array_listado();" onkeyup="teclear(event,this);" style="width: 200px;" type="text" value="" />
onFocus: Al recibir el enfoque, la matriz de datos se recargará con la lista actualizada de clientes, por lo que en un entorno multiusuario se podrán tener siempre los datos actualizados.
onKeyUp: Al soltar la pulsación de una tecla, se desencadenará la función que despliega el listado de nombres coincidentes. Igualmente en esta misma función se encuentran inmersos los procesos de selección de la lista y carga de datos del nombre seleccionado.
Por favor, no olviden comentar sus ideas para mejorar este artilugio.