Como mejorar el funcionamiento de las aplicaciones web con AJAX

Este artículo pretende ser una introducción a AJAX, un sistema para desarrollar aplicaciones web con procesamiento en servidor, sin necesidad de recargar la página.
Este pequeño reportaje explica cómo ganar en tiempo de respuesta del servidor y por tanto, aumentar la eficiencia en el desempeño de los desarrollos web, basado en el uso de PHP como tecnología de programación, más el uso de AJAX (Asynchronous JavaScript And XML).

Comenzaré por decir que yo no soy experto en el tema y que si bien, AJAX (anteriormente conocido como JSRS[Java Script Remote Scripting]) es un método que ya tiene varios años utilizándose. Hace unos meses que comencé a interesarme en AJAX y la información al respecto no era demasiada. Afortunadamente, para esta época, el uso de AJAX se ha extendido de forma abundante y debo decir que ya no sólo existe información, sino ejemplos y desarrollos varios basados en ella.

¿Qué es AJAX?

Bueno, como lo he dicho, a este momento ya hay mucha información técnica al respecto y muchos buenos conceptos. Creo que lo mejor será explicar en qué se diferencian los desarrollos tradicionales, con un desarrollo basado en AJAX, ya que es ahí donde radica el poder de esta combinación de tecnologías.

En un desarrollo tradicional, los clientes interactúan mediante el uso de formularios que hacen una petición. La misma es recibida por el servidor, procesada y reenviada de regreso en forma de respuesta al cliente. De esta manera, a veces se envía y reenvía toda una página web esperando tan solo regresar un dato, con lo cual, el ancho de banda se desperdicia, pues mucha de la información contenida en la respuesta, ya existía originalmente en la primera página.

En un desarrollo basado en AJAX es posible enviar peticiones al servidor enviando solo la información necesaria. El servidor recibirá la petición, la procesará y regresará sólo los datos necesarios a la página original. Con todo ello, lógicamente, ganamos bastante en ancho de banda y por tanto, en tiempo de respuesta del servidor. Al final, en el performance o funcionamiento de los desarrollos también se verá mejorado.

El ejemplo clásico, y algo que muy comúnmente se hace, es la carga de un objeto <select> con elementos determinados a partir de una elección anterior. Concretando, podemos tener dos selects uno con estados y otro con municipios. En el primero seleccionamos, por ejemplo, un estado de la República Mexicana. Una vez realizada esa elección, el segundo select se cargaría con la lista de municipios/delegaciones que hay dentro del estado seleccionado. El objetivo final es seleccionar un municipio/delegación del estado que hemos marcado antes.

Para hacernos una idea más exacta del objetivo de este ejercicio, podemos ver el ejemplo en marcha:

Nota: El ejemplo lo he desarrollado en PHP, pues es el lenguaje que utilizo, pero basta decir que puede usar cualquier tecnología que esté enfocada al Web.

En este caso tendremos un archivo principal con el formulario, un archivo .js que tiene la llamada al AJAX y un archivo .php que reciba el valor del estado elegido, lo procese y devuelva el resultado. A pesar de toda la complicación de tratar con un nuevo sistema como AJAX, el ejemplo es muy simple.

Veamos el código PHP del formulario

A continuación mostramos el código completo de la página del formulario. Luego explicaremos las líneas más importantes.

<?php include("funciones.php"); ?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><!-- InstanceBegin template="/Templates/usuario.dwt.php" codeOutsideHTMLIsLocked="false" -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<!-- InstanceBeginEditable name="doctitle" -->
<title>::: Prueba de carga de municipios:::</title>
<script language="javascript" src="ajax.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript">
function cargarContenido(){
var d1,contenedor;
contenedor = document.getElementById('contenedor');
d1 = document.QForm.estado.options[document.QForm.estado.selectedIndex].value;
ajax=nuevoAjax();
ajax.open("GET", "procesos.php?edo="+d1,true);
ajax.onreadystatechange=function() {
if (ajax.readyState==4) {
   contenedor.innerHTML = ajax.responseText
}
}
ajax.send(null)
}
</script>
</head>
<body>
   <table width="100%" border="0" cellspacing="2" cellpadding="0">
    <tr>
     <td align="center" scope="col">
   <form name="QForm" method="post" action="#">
    <table width="80%" border="0" align="center" cellspacing="4">
    <tr>
   <td width="37%" align="right">Estado </td>
    <td>

   <?php

   $xtra ='onChange="cargarContenido();"';
   impSelect("estado",$xtra,"");

   ?>
    </td>
   </tr>
   <tr align="left">
   <td width="37%" align="right">Municipio </td>
    <td>
  <div id="contenedor">
   <select name="municipio" class="navLink" id="municipio">
   <option value="-99">  </option>
   </select>
   </div>

  </td>
   </tr>
  </table>
</body>
</html>


Hasta aquí, habría que comentar lo siguiente:

<?php include("funciones.php"); ?>

El archivo funciones.php tiene una funcion llamada impSelect(), que recibe parámetros para buscar dentro de la tabla estado y municipio. Una vez obtenidos los registros, se encarga de pintar el objeto <select> y todos sus <option>. Esta función no es nada complicada y quedará para realización del lector.

<script language="javascript" src="ajax.js" type="text/javascript"></script>

Esto realiza la inclusión de una función para realizar un AJAX.

<script language="javascript" type="text/javascript">
// esta funcion se ejecuta al elegir un estado
function cargarContenido(){
var d1,contenedor;

contenedor = document.getElementById('contenedor');
//contenedor es el <div> , donde al final pintaremos el nuevo select

d1 = document.getElementById('estado').value;
// recibimos en una variable el valor del estado elegido

ajax=nuevoAjax();
//aqui creamos una instancia del objeto ajax

ajax.open("GET", "procesos.php?edo="+d1,true);
// con esto enviamos al archivo .php el valor del estado para que sea ejecutado

ajax.onreadystatechange=function() {
if (ajax.readyState==4) {
   //En esta parte del código, se revisa cuando el ha sido procesada la carga del AJAX
   contenedor.innerHTML = ajax.responseText
   //CON en esta línea, decimos que pinte el resultado en nuestro div "contenedor"
}
}
ajax.send(null)
// aqui se hace el envio del objeto
}
</script>

$xtra ='onChange="cargarContenido();"';
impSelect("estado",$xtra,"");


Como ya habiamos explicado, el archivo funciones.php contiene una función que pinta el <select> y que es la que mandamos llamar aquí. En resumidas cuentas, al query le estoy mandando el nombre de la tabla de la cual extraer la información ("estado"), que también se utiliza para nombrar el objeto <select> y que, como vimos arriba, es lo que recibe el objeto ajax y envía para procesamiento. También le envío un dato $xtra, que es el que pintará la función onChange() en el select, para así mandar a ejecutar el AJAX una vez elegido el estado.

<div id="contenedor">
  <select name="municipio" class="navLink" id="municipio">
  <option value="-99">  </option>
  </select>
</div>


En este trozo de código HTML vemos el segundo select, que está dentro del div="contenedor". Ya vimos arriba que este div es donde pintaremos el resultado del procesamiento de nuestro estado, recibido por el archivo procesos.php. Mientras tanto, pinto un select vacío para hacer precisamente el efecto de carga de contenido dentro de este primer select, cuando en realidad lo que hacemos es reemplazarlo por uno nuevo.

Código de ajax.js

Bien, ahora, pasemos a ver qué tiene el archivo ajax.js.

function nuevoAjax(){
  var xmlhttp=false;
  try {
   // Creación del objeto ajax para navegadores diferentes a Explorer
   xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
   // o bien
   try {
     // Creación del objet ajax para Explorer
     xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (E) {
     xmlhttp = false;
   }
  }

  if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
   xmlhttp = new XMLHttpRequest();
  }
  return xmlhttp;
}


Bueno, no hay mucho que decir al respecto. Sólo que este código es muy típico para crear el AJAX. Aunque se podría crear de otras maneras, este código funciona muy bien para la mayoría de los casos.

Código de procesos.php

Pasemos ahora al archivo procesos.php, que es el que ejecutamos para obtener la respuesta del AJAX.

<?
// incluyo mi archivo que contiene la función que imprime el objeto select
include("funciones.php");

// recibo mi valor de estado en la variable $edo
$edo = $_GET["edo"];

//llamo a la función para imprimir el select
impSelect("municipio","",$edo);
?>


En este caso, mando el nombre de mi tabla, que se llama municipio. Ahora no mando nada en la variable extra pues no se ejecutará nada en especial al seleccionar el municipio. Finalmente mando también el valor del estado, ya que mi query tomara este valor para decirle a la tabla que sólo me traiga los municipios que pertenezcan al estado seleccionado.

Esta llamada a la función es la que devolverá el AJAX, con lo cual, encima de mi select vacío, se pintará el select nuevo lleno con los municipios pertenecientes al estado seleccionado.

Conclusión

Pues eso es todo. Como hemos visto, para pintar sólo un select lleno de municipios pertenecientes a un estado, no era necesario enviar toda la página web de nuevo con el formulario entero, sino sólo el valor del estado seleccionado...

El efecto pueden verlo funcionando.

En adelante, les dejo a ustedes la tarea de investigar más sobre AJAX. Obviamente esta fue sólo una pequeña introducción. Únicamente basta con darle en cualquier buscador la palabra AJAX para comenzar a introducirse en el uso de esta recopilación de tecnologías.

Les dejo aquí un enlace a la sección especial de AJAX en Foros del Web:

Compartir

Comentarios

Cristian Bravo

09/12/2005
Es interesante la propuesta que AJAX nos ofrece a quienes nos dedicamos de forma profesional al desarrollo web.

Al autor, primero que todo felicitarlo al igual que al staff de DesarrolloWeb.com.

Les planteo mi inquietud:

Es facil darse cuenta de la cantidad de lineas que se escribio para realizar ese sencillo movimiento con los estados. Se podran imaginar que el crecimiento de codigo javascript es exponencial en relacion a la cantidad de funciones que necesitemos para el correcto funcionamiento de nuestra aplicacion. entonces, ¿cuanto codigo es capaz de parsear nuestro browser?.

les comento lo anterior por experiencia propia, en nuestra empresa nos dimos cuenta que el desarrollo del equipo de trabajo habia construido miles de lineas de codigo javascript que manejaba el glorioso dinamismo de ajax, a consecuencia de la ralentizacion de la aplicacion.

Para finalizar les cuento que estamos re desarrollando la aplicacion, esta vez, unificando lo mas posible las posibles funciones comunes y a espera de un framework manejador.

Saludos a todos.

Cristian Bravo
bigsupport.cl

Zagalet

09/12/2005
Muy buen tema, hace mucho tiempo que me tuve que crear mis combo-selects con iframes para crear este mismo efecto.
Ahora con Ajax se pueden realizar cosas muy visuales y efectivas pero tambien menos visuales pero mucho más efectivas como es el ejemplo de este articulo.

Para los que pedian la funcion.php, simplemente es crear el select como si lo escribierais a codigo pero con los elementos extraidos de la BDD.
Si quereis probar el efecto simulando como si fuese un acceso a BDD aqui teneis la funcion, pero esto seria libre de cada uno segun la necesidad de cada aplicacion.
--- funciones.php ---
<?
function impSelect($tabla,$llamada_salto,$valor)
{
if ($tabla==’estado’)
{
echo ’
<select name="’.$tabla.’" id="’.$tabla.’" ’.$llamada_salto.’>
<option selected>’.$tabla.’</option>
<option value="1">Espa&ntilde;a</option>
<option value="2">Francia</option>
<option value="3">Italia</option>
</select>’;
}
else
{
$llamada_salto=’OnChange="alert(’Has elegido:’+this.value)"’;
echo ’<select name="’.$tabla.’" id="’.$tabla.’" ’.$llamada_salto.’>
<option selected>’.$tabla.’</option>’;
if ($valor==’1’)
echo ’<option value="Madrid">Madrid</option><option value="Barcelona">Barcelona</option><option value="Tarragona">Tarragona</option>’;
if ($valor==’2’)
echo ’<option value="Paris">Paris</option><option value="Tolousse">Tolousse</option><option value="Poitiers">Poitiers</option>’;
if ($valor==’3’)
echo ’<option value="Roma">Roma</option><option value="Florencia">Florencia</option><option value="Pisa">Pisa</option>’;
echo ’</select>’;
}
}
?>
--- FIN de funciones.php ---

melchor

19/12/2005
A la atención del autor del artículo:

Todo funciona bien siguiendo tu ejemplo, tanto en el navegador Firefox como en IExplorer. El problema lo encuentro si los dos select de tu ejemplo los meto en un formulario e intento enviar mediante GET O POST los datos seleccionados por el usuario. Me encuentro con la sorpresa de que en IExplorer recivo correctamente los datos del formulario en el servidor. En cambio, en Firefox no recibo el dato del segundo select, no recibo justo lo que se 'repinté' con AJAX.

He observado que al usar IExplorer se crea un ActiveXObject("Msxml2.XMLHTTP"), en cambio, al usar Firefox se crea un XMLHttpRequest. Entiendo que ahí está la diferencia y el problema, pero no sé como solucionarlo y la verdad es que Firefox es un navegador muy extendido como para no tenerlo en cuenta. Gracias en cualquier caso.

Daniel

14/2/2006
Excelente explicación y muy buen ejemplo. Me sumo al colega que dijo que hubiera sido bueno dar el código de funciones.php.
De todos modos me ha resultado un artículo muy provechoso. Como aporte personal dejo un ejemplo que encontré navegando y del cual aprendí mucho también: http://www.zonaencuentros.com/ajax/ajax_ejemplo.php
Les mando un saludo.

Jorge Rubiano

23/2/2006
Me parece muy bueno el artículo, me funcionó de manera correcta el ejemplo expuesto, pero como se verá en el mismo, en el combo existe un carácter especial cuando se selecciona el estado Toledo, en el combo Municipio se carga tres los cuales son:
- Toledo la Capital.
- lllescas.
- Y parece ser que dice Ocaña.
En Mozilla donde esta el carácter especial en este caso la "ñ" sale un signo de interrogación, en IE esta opción no aparece y esto puede ser grave por que se pensaría que no existe en la Base de datos.
Para solucionar este incoveniente, en el archivo "procesos.php", que es el que recibe los datos que se están enviando por la función que crea el objeto Ajax, se deben adicionar tres líneas de código

header('Content-Type: text/xml; charset=ISO-8859-1');
mb_http_input("iso-8859-1");
mb_http_output("iso-8859-1");

Por lo que el archivo quedaría de esta forma:
<?
header('Content-Type: text/xml; charset=ISO-8859-1');
mb_http_input("iso-8859-1");
mb_http_output("iso-8859-1");
include("funciones.php");
$edo = $_GET["edo"];
impSelect("municipio","",$edo);
?>

En este caso como sólo se esta enviando un id que identifica la ciudad, y no el nombre de la misma, no es necesario adicionarle la función escape(), en la función cargarContenido(), pero sí ese fuera el caso deberiamos ponerla cuando se le esta asiganando a una variable, por ejemplo en la función cuando se le esta asignando a la variable d1, el valor seleccionado en el combo, la línea de código originalmente estaría así:
d1 = document.QForm.estado.options[document.QForm.estado.selectedIndex].value;
Con la función escape(); quedaría así:
d1 = escape(document.QForm.estado.options[document.QForm.estado.selectedIndex].value);
En esta página se explica el funcionamiento de esta función propia de Javascript: http://www.htmlpoint.com/javascript/corso/js_22.htm

Bueno y por último ya que la persona que escribio el documento, no nos dejo el archivo "funciones.php", aquí les muestro como lo solucione yo, para comparar criterios....

<?php
function impSelect($ncombo,$change,$buscar)
{
require_once("conectar.php");//Abró la BD
$consulta = mysql_query("SELECT * FROM tabla", $link);
if($ncombo == 'estado')
{
echo "<select name=$ncombo $change>";
while($fila = mysql_fetch_array($consulta))
{
extract($fila);
echo "<option value="$id1">$campo1</option>";
}
echo "</select>";
}
else
{
echo "<select name=$ncombo>";
$consulta = mysql_query("SELECT * FROM tabla2 where id=$buscar", $link);
while($fila = mysql_fetch_array($consulta))
{
extract($fila);
echo "<option value="$id2">$campo2</option>";
}
echo "</select>";
}
}
?>

Listo eso era todo lo queria decir...

mon

28/2/2006
La función que tu propones funciona de maravilla, gracias, sin embargo he podido comprobar que la solucion a los simbolos raros no esta definida. Hay que instalar una libreria especial para que funcione? me da el siguiente error:

Call to undefined function mb_http_input()

Tengo php 5.1.2. instalado

Ernesto Spiro Peimbert Andreakis

25/3/2006
Ajax, Mozilla e Internet Explorer.
Creo que es importante aparte de nombrar la manera en que se inicializa el objeto xmlhttprequest saber un pequeño detalle acerca de los navegadores.
Me encontraba en un proyecto para desarrollar un chat con AJAX. Creaba el objeto y al consultar el servidor no habia problemas con Mozilla. El problema vino al usar explorer.
Da la casualidad de que al enviar la peticion y checar un dato en el servidor usando explorer de repente se ciclaba la aplicacion y me desplegaba el resultado infinitamente.
Después de investigar me di cuenta que en algunas ocasiones el IE guarda una caché del archivo y no renueva la peticion lo que ocasiona que la peticion guarde una respuesta fija por la eternidad... ¿cómo se resolvió? simple, agregue un número rand a la direccion url pasandolo como parámetro tipo GET y de esta manera cada petición es "diferente".
Espero que esto les sea de ayuda.
Cualquier duda pueden contactarme en mi correo.
Saludos

Manolo

13/4/2006
Sobre lo de Jorge Rubiano de mb_http_input... A mí me funcionó un chat con ñ y acentos sólo con la cabecera que citas: header('Content-Type: text/html; charset=ISO-8859-1');

Damian

12/5/2006
el codigo fuente de los archivos no mostrados son algo así:
//Conectandose a Postgres
function Conectar_pg(){
//Reemplazar por los datos de tu tabla y base de datos.
$conn= pg_connect("user=<usuario> password=<clave>", "<base de datos>");
return ($conn);
}

function impSelect($tabla, $extra, $edo){
$con = Conectar_pg();
if ($tabla=="departamento" && $edo=="")
$sql = "SELECT * FROM $tabla ORDER BY nombre";
else
$sql = "SELECT * FROM $tabla WHERE id_departamento='$edo'";
$result= pg_query($con, $sql);

echo "<select name="$tabla" $extra> ";
echo "<option selected value=selecionar>Seleccione</option> ";
while ($row = pg_fetch_array($result)){
if($tabla=="departamento"){
printf ("<option value=%d>%s</option> ", $row[id_departamento], $row[nombre]);
}
else
printf ("<option value=%d>%s</option> ", $row[id_municipio], $row[nombre]);
}
//Close_pg($conn, $result);
echo "</select> ";
}

Simple y buen articulo.

JERÓNIMO SALAZAR RAMÍREZ

05/8/2006
Hola que tal, ese es uno de los mejores artículos que he visto y he de mencionar que en esta página son muchos.

Les sugiero que chequen la información que esta en esta dirección para entender mejor el problema.

http://developer.mozilla.org/es/docs/AJAX:Primeros_Pasos

Espero y les sirve para los que lean este artículo.

Raquel

04/11/2006
Hola. Muy claro el artículo. Pero quisiera saber como hago para que pueda salir con enlaces en el segundo formulario. Osea, en vez de mostrar con una ventana que ha sido seleccionado, quisiera saber como se hace para que se cargue un enlace saliente.
Gracias.

Belen

06/6/2007
SON...........GRANDIOSOS!!!!
Llevaba dias intentar algo asi, no comprendia lo d ajax... pero gracias al articulo y alos comentarios de TODOS USTEDES.. ya salio el problemita q tenia.....

Mil Gracias!!!

esteban769

15/1/2011
Interesante
Es una interesante propuesta ya que ami me sirvio por k estoy haciendo unos formularios para mi proyecto Gracias

kendri

30/11/2011
saludos
felicito al autor de este articulo esta muy bueno, seria bueno que explicara otros articulos parecidos...

kendri

01/12/2011
saludos
amigo, el articulo esta muy bueno espero que siga publicando mas que sea productivo para los desarrolladores que son nuevo en la programacion web,,,saludos....

kendri

02/12/2011
saludos
buenas noches compañero le sugieros a aquellos desarrolladores en php y ajax, q coloque mas articilo nuevos........seria posible eso.

kendri

03/12/2011
saludos
amigo, q posiblida habria de que sigan publicando mas ejercicios de estos, que son muy util para la comunidad...