Alters

Tips & Tricks: Overlay de eventos en JavaScript (II)

Buenas!

Vamos a ver rápidamente cómo tratar el solapamiento de eventos con AJAX...

Y es que AJAX puede resultar difícil de usar... ya que muchas veces se necesita de un elemento existente para que funcione bien...

Para empezar con los ejemplos, supondremos la siguiente llamada a función:

doAjax(url, query, getXML, divToChange, ev);

siendo los dos parámetros la URL completa; el tercer parámetro indica (con 1 o 0) si el resultado es o no XML.

El valor de divToChange es el id del div (o elemento) que queramos cambiar. Por otra parte, "ev" hace referencia a si el resultado ha de ser evaluado.

Pues bien, si "divToChange" hace referencia a un id inexistente, habrá un fallo en AJAX, por lo que siempre debemos comprobar que el elemento existe.

¿Y puede ser que no exista?

Pues, sí. Si hacemos varias cargas seguidas con AJAX/JS, puede ser que, al ser AJAX paralelo, intente acceder a un id que todavía no existe.

Para que esto no pase tenemos varias opciones:

a) Esperar un tiempo determinado
b) Evitar que AJAX sea paralelo

La primera opción tiene sus ventajas, pero posee un inconveniente que, para mí, es bastante obvio: dependiendo de la conexión que poseamos tardará un tiempo u otro.

Así, que, siempre que sea factible, al hacer varias cargas con AJAX deberíamos usar AJAX secucuencial.

Pero esto no es todo; si tenemos muchas llamadas AJAX seguidas, podemos hacer que AJAX pierda la petición y quedarnos sin resultado.

Es decir, suponed algo así:

for(i=0;i<20;i++){
  doAajax(url,query,0,'contenido'+i,0);
}

Al ser un bucle sin más, nuestro Request perderá las peticiones (se solaparán), saliendo solo el resultado de la última.

Para no perder las peticiones podríamos esperar, como en el primer caso... pero ¿cuánto?

Pues... un tiempo indefinido, el justo para que la petición termine.

Para ello haremos uso de "setTimeout", cuyo uso es:

window.setTimeout(function(){sentencia_a_ejecutar}, tiempo);

En nuestro caso, debemos embeber la llamada. Es decir, pasaríamos el código anterior al siguiente:

for(i=0;i<20;i++){
  doAjaxTimed(url,query,0,'contenido'+i,0);
}

function doAjaxTimed(url,query,getXML,divToChange,eval){
  window.setTimeout(function(){doAjax(url,query,getXML,divToChange,eval)}, t);
}

Y, , usamos "t", sin definir... con esto tardará lo que tenga que tardar... y los eventos no se solaparán.

Ahora vamos a otro caso de solapamiento de eventos:

Imaginad que queremos hacer el típico sistema de "select" para elegir país y ciudad. Al elegir un país cambian las ciudades mediante AJAX, y los países se cargan a posteriori con AJAX, de manera que:
<div class="decision">
  <select id="paises"><option value="0"<Seleccione</option></select>
  <select id="ciudades"><option value="0">Seleccione</option></select>
</div>
<script type="text/javascript"&gt;doAjax(url,query,0,"paises",0);//carga de paises</script>
Esto funciona a las mil maravillas para cargar las ciudades. Luego veremos el resto... pero ahora surge la duda: ¿Y si cargamos todo esto previamente con un AJAX?

Entonces, el script no se ejecuta, ya que no evaluamos ninguna sentencia. Tocará pensar algo...

¿Un timer? Pasa lo de siempre, debemos esperar...

He aquí una solución que me gusta más: un handler. Hacemos así:


<div class="decision">
  <select id="paises" onmouseover="carga();"><option value="0"<Seleccione</option></select>
  <select id="ciudades"><option value="0">Seleccione</option></select>
</div>

Y definimos en un fichero externo la función "carga()":

function carga(){
  if(document.getElementById('paises').options.length &gt; 1){
    return false;
  }

  doAjax(url,query,0,'paises',0);
  return false;
}

Y así, al tener el ratón por encima (antes de hacer click) se cargarán los países, sin que se note...

Y con esto podemos tener algo más controlado nuestro JS y AJAX.

Como final me gustaría añadir que estas entradas han sido algo raras y escasas, lo se... estoy demasiado liado con todo... a ver si los futuros cambios me sirven para ir a mejor!

Y como siempre,

¡Hasta la próxima!