Foros del Web » Programando para Internet » Javascript »

addEventListener para onload de imagen

Estas en el tema de addEventListener para onload de imagen en el foro de Javascript en Foros del Web. Hola, primero decir que javascript no es que lo domine, vamos, soy un simple aficionado ;) A ver si alguno me aclara algo sobre addEventListener ...
  #1 (permalink)  
Antiguo 03/04/2011, 19:04
 
Fecha de Ingreso: abril-2011
Mensajes: 4
Antigüedad: 13 años
Puntos: 0
addEventListener para onload de imagen

Hola, primero decir que javascript no es que lo domine, vamos, soy un simple aficionado ;)

A ver si alguno me aclara algo sobre addEventListener aplicado a una imagen cuando acabe de cargar, porque me saca de mis casillas, ya que no me funciona. Y cada vez que leo algo más, me lío más aún, si es que es posible.

Para más inri, Gecko (Firefox, Seamonkey, etc), en algunas versiones, da errores porque no acepta variables de un array para addEventListener, dando un cariñoso error NS_ERROR_XPC_BAD_CONVERT y esto me ha vuelto loco media tarde. (Ejemplo: addEventListener('load',funcion_a_ejecutar(var[]),false);)

Bueno, pero a lo que voy, no soy capaz de hacerlo funcionar para capturar el evento onload, o de fin de carga, de una imagen. En vez de capturar el fin de carga de la imagen, captura la carga del documento. Igual es que tiene que funcionar así, pero dado que onload, aplicado a un elemento img, no está permitido en el estándar..., ya me diréis a ver qué hago.

Datos en mi html relacionados, los que siguen:

Código:
<body onload="crear_capturas_de_eventos();">
Esto lo hago porque como javascript se ejecuta antes que la carga de el html, no puede encontrar el elemento (null), así que los creo a partir de body onload, llamando a esta función:

Código:
function crear_capturas_de_eventos(){
var imgtest = document.getElementById('xxx').addEventListener('load',iloaded('valor'),false);
}
Pues bien, lo que ocurre aquí es que la función iloaded se ejecuta incluso aunque no cargue la imagen (supongamos que no encuentra esa imagen). Al parecer, cuando se carga el documento, es cuando salta la captura del evento onload.

Dicho de otra manera, en vez de aplicarlo al elemento con id xxx, que es la imagen a vigilar, está vigilando la carga del documento.

Por qué, ni idea. Se me ocurre alguna cosa.

Veamos, inicialmente, la imagen con id xxx, tiene de valor src, nada, es decir:
Código:
<img src="" id="xxx">
Y se le crea un valor src via javascript con otra función en body via onload, es decir, en realidad, el body onload es así:
Código:
<body onload="crea_src_imagenes(); crear_capturas_de_eventos();">
Esta función es así porque no puede tener un valor src fijo la imagen porque el src siempre es diferente. Además de que para ejecutar otras funciones, me baso en el valor dado que tenga el src en un momento x.

¿Podría ser el problema que las imágenes tengan src creados dinámicamente?

Si habéis hecho vosotros esto, dadme un ejemplo, porque, la verdad, me estoy volviendo loco y en el foro no lo he encontrado.

P.D.: ¿podría alguien explicar, para dummies, qué hace realmente el tercer parametro de addEventListener (buleano true/false)?
  #2 (permalink)  
Antiguo 03/04/2011, 19:56
Avatar de Panino5001
Me alejo de Omelas
 
Fecha de Ingreso: mayo-2004
Ubicación: -34.637167,-58.462984
Mensajes: 5.148
Antigüedad: 20 años
Puntos: 834
Respuesta: addEventListener para onload de imagen

Hay varias consideraciones y es un tema escabroso.
Esto, por ejemplo, está mal:
Código PHP:
document.getElementById('xxx').addEventListener('load',iloaded('valor'),false); 
Porque el segundo argumento de addEventListener espera una referencia a una función y no una invocación a una función. Es decir, hay que colocar sólo el nombre de la función si es que esta no requiere argumentos y ya está definida o envolverla en una función anónima en cualquier otro caso:
Código PHP:
document.getElementById('xxx').addEventListener('load',function(){iloaded('valor');},false); 
Pero además, hay que considerar otras cosas. Por ejemplo, la carga de las imágenes suele suceder antes que la carga de la página, así que para cuando se produce el onload de body o el window.onload, ya se produjo el image.onload y lo más probable es que no se ejecute el manejador asignado a ese evento si lo asigno más tarde.
Y ahí se presenta un problema, porque para asignar un evento a un elemento este debe estar disponible en el DOM y para eso hay 4 posibilidades:
1-ver si se produjo el evento DOMContentLoaded
2-asignar los eventos como atributos del tag img
3-asignar los eventos con scripts escritos justo después de los tags img
4-esperar el window.onload o el body onload
La 4 ya vimos que no sirve.
La 1 funciona sólo en navegadores estandar, pero no en Explorer y los apaños que suelen usarse (document.readyState=='complete', por ejemplo) suelen ocurrir luego de la carga de las imágenes, con lo que terminamos igual que con la opción 4.
Y la 2 y 3 no son muy cómodas ni limpias.
Dependiendo del caso, puede usarse DOM 1, que funciona siempre y sólo hay que verificar, para que el evento se produzca siempre, que la imagen no esté cacheada:
Código PHP:
<script type="text/javascript">
var 
i=new Image();
i.onload=function(){alert('listo');}
i.src='img2/5.jpg';//o, para evitar caché: i.src='img2/5.jpg?'+new Date().getTime();
</script> 
O usar temporizadores para asignar los eventos:
Código PHP:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<
html xmlns="http://www.w3.org/1999/xhtml">
<
head>
<
meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<
title>Documento sin título</title>
<
script type="text/javascript">
function 
addEvent(obj,fun,type){ 
    if(
obj.addEventListener){ 
        
obj.addEventListener(type,fun,false); 
    }else if(
obj.attachEvent){ 
        var 
f=function(){ 
            
fun.call(obj,window.event); 
        } 
        
obj.attachEvent('on'+type,f); 
        
obj[fun.toString()+type]=f
    }else{ 
        
obj['on'+type]=fun
    } 

(function 
loadImage(){
        if(!
document.images[0]){
            return 
setTimeout(loadImage,0);    
        }
        
addEvent(document.images[0],function(){alert(['a','b','b'])},'load');
})();
</script>

</head>

<body>
<img src="img2/29.jpg" width="1024" height="768" />
</body>
</html> 
O temporizadores para verificar la propiedad complete de las imágenes cuya carga necesitemos controlar:
http://www.forosdelweb.com/3342764-post13.html
En cuanto a cómo funcionan los eventos del DOM, considerando que en explorer funcionan también de manera diferente, te recomiendo esta lectura:
http://kusor.net/traducciones/brainj...vents1.es.html
  #3 (permalink)  
Antiguo 03/04/2011, 20:37
Avatar de zerokilled
Javascripter
 
Fecha de Ingreso: abril-2009
Ubicación: Isla del Encanto, La Borinqueña [+>==]
Mensajes: 8.050
Antigüedad: 15 años
Puntos: 1485
Respuesta: addEventListener para onload de imagen

buenas...

nota: edito porque gran parte del tema ya lo explico panino. al momento de comenzar a redactar no estaba su respuesta. tal parece que me heche mucho tiempo en redactar.

el tercer argumento de addEventListener controla en que etapa de la propagacion el listener debe capturar el objeto event generado por el evento. hay tres etapas: CAPTURE, TARGET y BUBBLE. CAPTURE, basicamente es cuando el objeto event recorre el camino desde el contexto mas alto en la jerarquia de elementos -usualmente DOM Window- hasta el elemento que producio el evento; TARGET es el elemento en si que producio el evento; y BUBBLE es el reverso de CAPTURE, desde el elemento hacia el elemento mas alto de la jerarquia. lo que significa si uno de los elementos del camino contiene un listener para el tipo de evento generado, el listener lo va a capturar de acuerdo a dos factores: el comportamiento indicado en el tercer argumento de addEventListener, y si el objeto event puede recorrer el camino de regreso, o sea BUBBLE. de modo que un objeto event que no puede recorrer el camino de regreso no sera capturado por un listener que captura en la etapa BUBBLE.

__________________
la maldad es una virtud humana,
y la espiritualidad es la lucha del hombre contra su maldad.

Última edición por zerokilled; 03/04/2011 a las 20:43 Razón: gran parte del tema respondido por panino
  #4 (permalink)  
Antiguo 04/04/2011, 09:18
 
Fecha de Ingreso: abril-2011
Mensajes: 4
Antigüedad: 13 años
Puntos: 0
Respuesta: addEventListener para onload de imagen

Cita:
Iniciado por Panino5001 Ver Mensaje
Hay varias consideraciones y es un tema escabroso.
Eso seguro. Enrevesado más bien :S
Cita:
Iniciado por Panino5001 Ver Mensaje
Esto, por ejemplo, está mal:
Código PHP:
document.getElementById('xxx').addEventListener('load',iloaded('valor'),false); 
Porque el segundo argumento de addEventListener espera una referencia a una función y no una invocación a una función. Es decir, hay que colocar sólo el nombre de la función si es que esta no requiere argumentos y ya está definida o envolverla en una función anónima en cualquier otro caso:
Código PHP:
document.getElementById('xxx').addEventListener('load',function(){iloaded('valor');},false); 
Vale, el problema es que los navegadores lo aceptan (Opera y Firefox).

De todas formas, el envolverla... ¿no podría ser con una variable? Es que las capturas de eventos tendría que hacerlas con un while (porque lo mismo tengo 4 para crear, que 30 y no es cuestión de ponerlas una a una), entonces las creo así y, según tus indicaciones, ¿sería esto correcto? (si es que se admiten variables como segundo argumento, claro):

Código:
function crear_capturas_de_eventos(){

z = 1;
cuoc = 0;

var otrafuncion = iloaded(vararray[[z]]);
		
	while(z < unvalor+1){
		var imgtest[z]= document.getElementById(otroarray[z]).addEventListener('load',otrafuncion,false);
		cuoc++;
		}
		if(z > unvalor){
		break;
		}
		z++;
	}

}
Esta es una adaptación rápida de un while que tengo por ahí, no tengas en cuenta errores evidentes, es para que te hagas una idea de cómo crearía las capturas de eventos y para saber si sería posible meter la variable otrafuncion como segundo argumento, para así poderle pasar a la función iloaded los argumentos necesarios desde el array de ejemplo que pongo aquí vararray.

Si te fijas, si hago lo que tú dices de llamar a una función que envuelva la función iloaded, no podría pasarle valores distintos. Digo esto porque "z" la reseteo unas cuantas veces a lo largo de varias funciones del script y, aunque es una variable global se manipula, mayormente, de forma local, con reseteos, como digo. Aunque supongo que sí podría hacerlo, pero mira que es rebuscado :P Crear una función para llamar a otra función es un poco redundante. Opinión de un iletrado de javascript como yo :P

Cita:
Iniciado por Panino5001 Ver Mensaje
Pero además, hay que considerar otras cosas. Por ejemplo, la carga de las imágenes suele suceder antes que la carga de la página, así que para cuando se produce el onload de body o el window.onload, ya se produjo el image.onload y lo más probable es que no se ejecute el manejador asignado a ese evento si lo asigno más tarde.
Mira, eso de que cargan las imágenes antes que la página no lo sabía.

Pero ojo a mi código. Mis imágenes no cargan porque tienen, de inicio, un src="", y, además, hasta que no se carga la función crea_src_imagenes(); en el onload del tag body, no se empiezan a cargar las imágenes que quiero.

Así que ese caso, en principio, no ocurriría, ¿no?

Cita:
Iniciado por Panino5001 Ver Mensaje

Y ahí se presenta un problema, porque para asignar un evento a un elemento este debe estar disponible en el DOM y para eso hay 4 posibilidades:

Dependiendo del caso, puede usarse DOM 1, que funciona siempre y sólo hay que verificar, para que el evento se produzca siempre, que la imagen no esté cacheada:
Código PHP:
<script type="text/javascript">
var 
i=new Image();
i.onload=function(){alert('listo');}
i.src='img2/5.jpg';//o, para evitar caché: i.src='img2/5.jpg?'+new Date().getTime();
</script> 
El problema aquí es que el evento onload no está permitido para el elemento img, y es por esto que estoy buscando usar el addEventListener. Se ha vuelto casi un reto :D

Cita:
Iniciado por Panino5001 Ver Mensaje
O usar temporizadores para asignar los eventos:
[...]
O temporizadores para verificar la propiedad complete de las imágenes cuya carga necesitemos controlar:
[url]http://www.forosdelweb.com/3342764-post13.html[/url]
En cuanto a cómo funcionan los eventos del DOM, considerando que en explorer funcionan también de manera diferente, te recomiendo esta lectura:
[url]http://kusor.net/traducciones/brainjar.es/events1.es.html[/url]
Uy, temporizadores. Ese talón de aquiles. Ahí sí que no me meto. Usando Timeouts soy un jodido desastre. Nunca me funcionan. Hace un tiempo los intenté usar para crear un delay para un onmouseout y que se ocultara un div y no sé si es que no sabía usar el clearTimeout o qué, pero no había manera de parar el timeout :_(

De todas formas, en ese código que me has puesto, usas attachEvent y addEvent... igual es porque ya tengo la cabeza echa un lío, pero, ¿eso no era para IE sólo?

Gracias por los links, pero yo creo que cuanto más leo más me lío, por eso venía a preguntar. Intentaré echarles un ojo, a ver si entiendo algo.



Cita:
Iniciado por zerokilled Ver Mensaje
buenas...

el tercer argumento de addEventListener controla en que etapa de la propagacion el listener debe capturar el objeto event generado por el evento. hay tres etapas: CAPTURE, TARGET y BUBBLE. CAPTURE, basicamente es cuando el objeto event recorre el camino desde el contexto mas alto en la jerarquia de elementos -usualmente DOM Window- hasta el elemento que producio el evento; TARGET es el elemento en si que producio el evento; y BUBBLE es el reverso de CAPTURE[...]

Vale, a ver, pero false es capture y true es bubble, ¿no? Lo que no entiendo es por qué tiene que recorrer todos los elementos si tú ya le tienes indicado uno con getElementById :-? Así que mi pregunta es, ¿es necesario entonces el true y el false?
  #5 (permalink)  
Antiguo 04/04/2011, 10:25
Avatar de zerokilled
Javascripter
 
Fecha de Ingreso: abril-2009
Ubicación: Isla del Encanto, La Borinqueña [+>==]
Mensajes: 8.050
Antigüedad: 15 años
Puntos: 1485
Respuesta: addEventListener para onload de imagen

Cita:
Iniciado por webyg Ver Mensaje
El problema aquí es que el evento onload no está permitido para el elemento img, y es por esto que estoy buscando usar el addEventListener. Se ha vuelto casi un reto :D

...

Vale, a ver, pero false es capture y true es bubble, ¿no? Lo que no entiendo es por qué tiene que recorrer todos los elementos si tú ya le tienes indicado uno con getElementById :-? Así que mi pregunta es, ¿es necesario entonces el true y el false?
aunque el atributo onload no es aceptado como valido por W3.org, eso no significa que no puedes agregar dicho evento a traves de javascript. de hecho, tecnicamente cualquier elemento puede contener cualquier tipo de evento. la activacion de los eventos esta dado por dos factores: si el elemento es capaz de producir dicho evento o si el camino recorrido por objeto event se encuentra con dicho elemento.

y sobre los valores booleanos, true es para la fase capture y false para la fase bubble. si no se le indica un valor al tercer parametro, el valor por defecto deberia ser false. aunque si bien recuerdo algunos navegadores requieren el uso explicito del tercer parametro. la razon para que el objeto complete ese recorrido es para proveer mas dinamismo. por ejemplo, puedes tener dos listener para el mismo tipo de evento, cada uno realizando tareas distintas.

__________________
la maldad es una virtud humana,
y la espiritualidad es la lucha del hombre contra su maldad.
  #6 (permalink)  
Antiguo 04/04/2011, 10:49
Avatar de Panino5001
Me alejo de Omelas
 
Fecha de Ingreso: mayo-2004
Ubicación: -34.637167,-58.462984
Mensajes: 5.148
Antigüedad: 20 años
Puntos: 834
Respuesta: addEventListener para onload de imagen

Bueno, no entiendo del todo bien tu objetivo. Habría que ver un poco tu código para poder entenderlo.
No obstante eso, todavía hay algunos errores de concepto.
Lo que mencionás acerca de que los navegadores Firefox y Ópera aceptaban tu código con la invocación de la función en lugar de una referencia a la función como segundo argumento de addEventListener es un error de concepto: en ese caso no están asignando una función al evento (una función que sólo se ejecutará al producirse el evento) sino el retorno de una función que se ejecuta en el mismo momento en que se está creando el evento.
Se ve más claro en este ejemplo:
Código PHP:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<
html xmlns="http://www.w3.org/1999/xhtml">
<
head>
<
meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<
title>Documento sin t&#237;tulo</title>
<script type="text/javascript">
function 
test(){
    
alert(1);    
}
function 
test2(){
    
alert(2);
}
</script>



</head>

<body>
<div id="pp">hacer click</div>
<script type="text/javascript">
document.getElementById('pp').addEventListener('click',test,false);
</script>
<div id="pp2">hacer click</div>
<script type="text/javascript">
document.getElementById('pp2').addEventListener('click',test2(),false);
</script>

</body>
</html> 
Si lo ejecutás, vas a ver que cuando el intérprete alcanza la línea que contiene test2() ejecuta de inmediato la función test2 (cosa que no sólo no es deseable normalmente sino que además, dependiendo de cómo haya sido esa función definida, puede traer errores), pero luego, si hacés click en el elemento cuyo id es pp2, la función no vuelve a ejecutarse. Y como verás, no depende de si la función tiene o no argumentos: el problema son los paréntesis, ya que el intérprete al "verlos" ejecutará la función de inmediato.

En cuanto a que el onload no está permitido en el tag image, supongo que te estarás refiriendo a xhtml y a usarlo como atributo, porque en javascript no hay problemas en usarlo (y creo que en HTML 5 incluso está permitido su uso como atributo, pero de esto no estoy seguro).
Edito:
Esta vez me ganó zerokilled
  #7 (permalink)  
Antiguo 05/04/2011, 10:42
 
Fecha de Ingreso: abril-2011
Mensajes: 4
Antigüedad: 13 años
Puntos: 0
Respuesta: addEventListener para onload de imagen

Cita:
Iniciado por Panino5001 Ver Mensaje
Y como verás, no depende de si la función tiene o no argumentos: el problema son los paréntesis, ya que el intérprete al "verlos" ejecutará la función de inmediato.
Aaaaah, demonios, vale, (con esto y lo que dices más arriba) entonces por eso se ejecutaba sóla la función, incluso sin que llegase la hora.

Pues nada, sólo me queda meterla, pues, dentro de otra función. Y ya de paso pruebo lo de meterla dentro de una variable, para quitarme también la espina :D Aunque por lo que me has dicho, ya me queda claro por qué tampoco funcionaría.

Cita:
Iniciado por Panino5001 Ver Mensaje
En cuanto a que el onload no está permitido en el tag image, supongo que te estarás refiriendo a xhtml y a usarlo como atributo, porque en javascript no hay problemas en usarlo (y creo que en HTML 5 incluso está permitido su uso como atributo, pero de esto no estoy seguro).
Edito:
Esta vez me ganó zerokilled
Nada, os repondo a los dos igual ;)

Si lo del onload en una imagen ya lo había hecho y es como lo tengo, hasta que entendiera el dichoso addEventListener, pero si me preocupo por hacerlo acorde a lo que dice el validador (que está mal), pues... eso.

Como 4.01 Transitional también da el error. Si por problemas supongo que no habría, porque se ejecuta, pero es lo que decía antes.

Es una página normalita, ni xml, ni nada. Html y javascript. De ahí no paso.


Y gracias por la última explicación zerokilled. Creo que eso ya lo tengo algo más claro.

Gracias a los dos :)
  #8 (permalink)  
Antiguo 05/04/2011, 18:05
 
Fecha de Ingreso: abril-2011
Mensajes: 4
Antigüedad: 13 años
Puntos: 0
Respuesta: addEventListener para onload de imagen

Nada, al final, tras unas cuentas pruebas..., conclusiones:

1.- Sí, los eventos se pueden crear dinámicamente, y eso no da problema,

2.- Se creen como se creen los eventos, tienen que ejecutar siempre lo mismo, si no, toca crear tantas funciones como eventos tengamos, porque no aceptan argumentos y, aunque los acepten (truquillo que he encontrado por ahí), no guardan los valores de los argumentos como algo fijo para ejecutar en el futuro. Es decir, es un coñazo crear eventos mediante addEventListener.


Con lo que digo en el punto 2 me refiero a que si, al menos, cuando se crea el evento, se guardase lo que en ese momento se pide que se ejecute, no habría problema, pero no es así. Así pues, si tenemos argumentos variables, ocurre que (siguiendo mi primer ejemplo), usando este truquillo:

Código PHP:
var imgtest[z] = document.getElementById(z).addEventListener('load', function(){iloaded([z])}, false); 
Como no se guarda dentro de la variable imgtest lo que se le manda en cada momento (recordad que mi imgtest era un array), es decir, que iloaded se ejecute con el argumento Z con el valor que tenía en ese momento de crear el evento.... pues no funciona el crear eventos dinámicamente. Toma el que tiene Z en el momento de la ejecución.

Vamos, un cachondeo xDDD

Así que tocaría crear, a mano, tantas funciones como eventos tengamos y necesitemos, pasando los argumentos necesarios para cada función/evento.

Como decía, un coñazo.

Etiquetas: onload
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 12:30.