Foros del Web » Programando para Internet » Javascript »

Aplicar una funcion a un objeto creado dinamicamente

Estas en el tema de Aplicar una funcion a un objeto creado dinamicamente en el foro de Javascript en Foros del Web. Hola señores Prepare una funcion que reconoce en la pagina todos los elementos que tienen "title", los elimina y al hacer "onmouseover" sobre estos muestra ...
  #1 (permalink)  
Antiguo 09/01/2010, 19:32
Avatar de junihh  
Fecha de Ingreso: febrero-2004
Ubicación: República Dominicana
Mensajes: 997
Antigüedad: 20 años, 2 meses
Puntos: 7
Aplicar una funcion a un objeto creado dinamicamente

Hola señores

Prepare una funcion que reconoce en la pagina todos los elementos que tienen "title", los elimina y al hacer "onmouseover" sobre estos muestra un tooltip con la informacion que tomo del title.

La funcion hace bien su trabajo, pero me encontre en un proyecto en proceso con la situacion que debia generar ciertos elementos dinamicamente con JS. Eso no es problema, el problema es que la funcion mencionada carga solo una vez, asi que hice una version de la anterior para aplicar a elementos independientes.

Ambas funciones tienen predeterminado internamente los eventos "onmouseover" y "onmouseout", lo que me forza que a los objetos unicos les deba aplicar la funcion de esta forma:

Código HTML:
<a href="mailto:[email protected]" title="[email protected]" id="msgemail">nuestro email</a>
<script type="text/javascript">setObjTitle("msgemail");</script> 
Existe algun otro metodo para aplicar una funcion a un objeto sin necesidad de eventos en el objeto, o sea, sin tener que aplicar onmouseover-onmouseout directamente en el ??

No se si fui del todo claro con mi duda, asi que me avisan para tratar de explicarme mejor. De antemano, muy agradecido por cualquier ayuda o idea.
__________________
JuniHH
- Mi blog
- Mi portafolio
  #2 (permalink)  
Antiguo 09/01/2010, 20:05
Avatar de David
Moderador
 
Fecha de Ingreso: abril-2005
Ubicación: In this planet
Mensajes: 15.720
Antigüedad: 19 años
Puntos: 839
Respuesta: Aplicar una funcion a un objeto creado dinamicamente

No entendí muy bien. Si lo que quieres es agregar listeners al evento, y no reemplazar los que ya tiene el elemento, puedes usar addEventListener/attachEvent
__________________
Por favor, antes de preguntar, revisa la Guía para realizar preguntas.
  #3 (permalink)  
Antiguo 09/01/2010, 20:27
Avatar de Tecna  
Fecha de Ingreso: enero-2010
Mensajes: 291
Antigüedad: 14 años, 3 meses
Puntos: 45
Respuesta: Aplicar una funcion a un objeto creado dinamicamente

Buenas,

no te he entendido muy bien, en especial lo de que después de eliminar los elementos con title hagas "onmouseover" sobre ellos(¿después de eliminarlos?). A parte de eso los controladores de eventos se especifican bien como cadenas de código javascript en los atributos del HTML o bien como propiedades javascript de objetos, que son funciones a las que se puede llamar en cualquier momento. Así que creo que podrías volver a llamar a la función original cada vez que crearas un elemento nuevo asignándole un evento con addEventListener o incluso a otra cuantas veces necesites mediante su propiedad correspondiente, que precisamente es por lo que se recomienda hacerlo como propiedad mejor que como atributo . Suerte¡
  #4 (permalink)  
Antiguo 10/01/2010, 07:24
Avatar de junihh  
Fecha de Ingreso: febrero-2004
Ubicación: República Dominicana
Mensajes: 997
Antigüedad: 20 años, 2 meses
Puntos: 7
Respuesta: Aplicar una funcion a un objeto creado dinamicamente

@Tecna: Dentro de la funcion tengo una variable donde luego de leer el title guardo el valor, solo entonces borro el title del objeto para que no salga al mismo tiempo del tooltip.

@Tecna y @David: Ambas funciones tienen 3 eventos: onmouseover, onmouseout y onmousemove (este ultimo para seguir la posicion del mouse). Entiendo lo de agregar un listener extra, pero el problema con hacerlo es que quita recursos al navegador y no me gustaria, quiero que mi aplicacion sea ligera pese a la cantidad de JS que uso en ella.

Para estar mas claros, aqui les dejo el codigo de todo el script:


Código HTML:
function setAllTitles ()
{
    var objs = document.getElementsByTagName('*');
    var tt;
    //
    for (var i = 0; i < objs.length; i++)
    {
	   if (objs[i].title)
	   {
		  setTT (objs[i]);
	   }
    }
    //
    function setTT (ob)
    {
	   var tit = ob.title;
	   ob.removeAttribute ('title');
	   //
	   ob.onmouseover = function (e)
	   {
		  tt = document.createElement ('div');
		  tt.style.backgroundColor = '#000';
		  tt.style.fontFamily = 'Helvetica, Arial, sans-serif';
		  tt.style.fontSize = '10px';
		  tt.style.color = '#FFF';
		  tt.style.border = 'solid 1px #FFF';
		  tt.style.padding = '6px 6px 4px 6px';
		  tt.style.position = 'absolute';
		  tt.style.display = 'none';
		  tt.style.borderRadius = '4px';
		  tt.style.MozBorderRadius = '4px';
		  tt.style.WebkitBorderRadius = '4px';
		  tt.style.KhtmlBorderRadius = '4px';
		  tt.id = 'lyrtooltip';
		  tt.innerHTML = tit;
		  document.body.appendChild (tt);
		  tt.style.zoom = 1;
		  //
		  document.onmousemove = function (evt)
		  {
			 tt.style.left = ( parseInt (mouseX(evt)) + 15 ) + 'px';
			 tt.style.top = ( parseInt (mouseY(evt)) - 5 ) + 'px';
			 tt.style.display = 'block';
		  }
	   }
	   //
	   ob.onmouseout = function ()
	   {
		  tt.style.display = 'none';
		  document.body.removeChild (tt);
	   }
    }
}

function setObjTitle (id)
{
    var ob = document.getElementById(id);
    var tit = ob.title;
    var tt;
    //
    ob.removeAttribute ('title');
    //
    ob.onmouseover = function (e)
    {
	   tt = document.createElement ('div');
	   tt.style.backgroundColor = '#000';
	   tt.style.fontFamily = 'Helvetica, Arial, sans-serif';
	   tt.style.fontSize = '10px';
	   tt.style.color = '#FFF';
	   tt.style.border = 'solid 1px #FFF';
	   tt.style.padding = '6px 6px 4px 6px';
	   tt.style.position = 'absolute';
	   tt.style.display = 'none';
	   tt.style.borderRadius = '4px';
	   tt.style.MozBorderRadius = '4px';
	   tt.style.WebkitBorderRadius = '4px';
	   tt.style.KhtmlBorderRadius = '4px';
	   tt.id = 'lyrtooltip';
	   tt.innerHTML = tit;
	   document.body.appendChild (tt);
	   tt.style.zoom = 1;
	   //
	   document.onmousemove = function (evt)
	   {
		  tt.style.left = ( parseInt (mouseX(evt)) + 15 ) + 'px';
		  tt.style.top = ( parseInt (mouseY(evt)) - 5 ) + 'px';
		  tt.style.display = 'block';
	   }
    }
    //
    ob.onmouseout = function ()
    {
	   tt.style.display = 'none';
	   document.body.removeChild (tt);
	   document.onmousemove = null;
    }
}

function mouseX (evt)
{
    if (!evt) evt = window.event;
    if (evt.pageX) return evt.pageX; else if (evt.clientX) return evt.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
    else return 0;
}

function mouseY (evt)
{
    if (!evt) evt = window.event;
    if (evt.pageY) return evt.pageY; else if (evt.clientY) return evt.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
    else return 0;
}

De no haber otra alternativa a los listener, me pueden aclarar como aplicarlo ??
__________________
JuniHH
- Mi blog
- Mi portafolio
  #5 (permalink)  
Antiguo 10/01/2010, 08:13
Avatar de junihh  
Fecha de Ingreso: febrero-2004
Ubicación: República Dominicana
Mensajes: 997
Antigüedad: 20 años, 2 meses
Puntos: 7
Respuesta: Aplicar una funcion a un objeto creado dinamicamente

Hola señores

De todos modos preferi dividir la funcion y aplicarla con eventos directamente al objeto de esta forma:

Código HTML:
function tooltipOverThis (obj)
{
    var ob = document.getElementById(obj.id);
    //
    var tit = ob.title;
    window.tempObjTitle = tit;
    ob.removeAttribute ('title');
    //
    var tt = document.createElement ('div');
    tt.style.backgroundColor = '#000';
    tt.style.fontFamily = 'Helvetica, Arial, sans-serif';
    tt.style.fontSize = '10px';
    tt.style.color = '#FFF';
    tt.style.border = 'solid 1px #FFF';
    tt.style.padding = '6px';
    tt.style.position = 'absolute';
    tt.style.display = 'none';
    tt.id = 'lyrtooltip';
    tt.innerHTML = tit;
    document.body.appendChild (tt);
    tt.style.zoom = 1;
    //
    document.onmousemove = function (evt)
    {
	   tt.style.left = ( parseInt (mouseX(evt)) + 15 ) + 'px';
	   tt.style.top = ( parseInt (mouseY(evt)) - 5 ) + 'px';
	   tt.style.display = 'block';
    }
}
function tooltipOutThis (obj)
{
    document.getElementById(obj.id).title = window.tempObjTitle;
    //
    var tt = document.getElementById('lyrtooltip');
    tt.style.display = 'none';
    document.body.removeChild (tt);
    document.onmousemove = null;
}
Código HTML:
<div title="El titulo con ID" id="este" onmouseover="tooltipOver(this);" onmouseout="tooltipOut(this);">Esto es un div con title y ID</div> 
__________________
JuniHH
- Mi blog
- Mi portafolio

Última edición por junihh; 10/01/2010 a las 08:24
  #6 (permalink)  
Antiguo 10/01/2010, 08:30
Avatar de Panino5001
Me alejo de Omelas
 
Fecha de Ingreso: mayo-2004
Ubicación: -34.637167,-58.462984
Mensajes: 5.148
Antigüedad: 19 años, 11 meses
Puntos: 834
Respuesta: Aplicar una funcion a un objeto creado dinamicamente

Lo que normalmente se hace para crear un tooltip es crear un único elemento para mostrar y ocultar y, en función a cuál es el elemento que dispara su aparición, definir su contenido con innerHTML o DOM (innerHTML es más rápido y como ya es parte del estandar html 5, mejor). De esa manera evitás incorporar al DOM un elemento adicional cada vez que necesitás mostrar el tooltip. Para ocultarlo, basta con definirlo con position: absolute y, por ejemplo, top:-1500px; Y para mostrarlo, ahí sí usar la posición del mouse (ligeramente desplazado de esa posición normalmente).
Ya que te interesa la optimización, ojo con la manera en que definís los bucles. Tal como estás ubicando la condición en tu bucle, la propiedad length es evaluada en cada iteración. Mejor crear una variable (var l=algo.length) y usar esa variable dentro del bucle (i<l). De esa manera, la propiedad es evaluada sólo una vez.
  #7 (permalink)  
Antiguo 10/01/2010, 09:02
Avatar de junihh  
Fecha de Ingreso: febrero-2004
Ubicación: República Dominicana
Mensajes: 997
Antigüedad: 20 años, 2 meses
Puntos: 7
Respuesta: Aplicar una funcion a un objeto creado dinamicamente

@Panino5001: En el caso de "length" fue porque solo lo use en ese punto y hala una vez, pero ya lo corregi. Tienes tambien la razon sobre el objeto en si mismo, ya que en ambos codigos que puse los elementos se generan cada vez que se llaman las funciones, por lo que tambien habria optimizacion alli. Muchisimas gracias por tus sugerencias, siempre vienen bien.
__________________
JuniHH
- Mi blog
- Mi portafolio
  #8 (permalink)  
Antiguo 10/01/2010, 09:19
Avatar de Panino5001
Me alejo de Omelas
 
Fecha de Ingreso: mayo-2004
Ubicación: -34.637167,-58.462984
Mensajes: 5.148
Antigüedad: 19 años, 11 meses
Puntos: 834
Respuesta: Aplicar una funcion a un objeto creado dinamicamente

En cuanto a los eventos hay otras optimizaciones que podés hacer. Sucede que en Explorer (no sé si se solucionó en la versión 8, pero antes ocurría así) maneja 2 motores diferentes para objetos DOM y objetos javascript (2 mundos) y a veces tiene problemas para relacionar ambos mundos y cuando intentamos destruir algo en un mundo termina no destruyéndose porque hay referencias a ese mismo objeto en el otro mundo. Algo que propicia eso es declarar los eventos de esta manera:
Código PHP:
objeto.onclick=function(){...} 
Una manera de no propiciar eso es colocar los eventos vía DOM **. El problema es de nuevo Explorer, que usa su propio estandar y para agregar eventos usa el método attachEvent. Los navegadores estandar usan el método addEventListener. Por eso hay que buscar un camino que se adapte a cada navegador. Para eso pudés usar funciones como esta:
Código PHP:
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 
removeEvent(obj,fun,type){
    if(
obj.removeEventListener){
        
obj.removeEventListener(type,fun,false);
    }else if(
obj.detachEvent){
        
obj.detachEvent('on'+type,obj[fun.toString()+type]);
        
obj[fun.toString()+type]=null;
    }else{
        
obj['on'+type]=function(){}
    }
        

que sirven para agregar y quitar eventos respectivamente.
Y se usarían, por ejemplo de esta manera:
Código PHP:
addEvent(document.getElementById('algo'),function(e){alert(this.id);},'click'); 
Pero para ver bien los eventos te recomiendo este artículo:
http://kusor.net/traducciones/brainj...rodom1.es.html
**Ojo, esto no soluciona totalmente el problema, pero lo mejora bastante.

Última edición por Panino5001; 10/01/2010 a las 09:25
  #9 (permalink)  
Antiguo 10/01/2010, 11:56
Avatar de junihh  
Fecha de Ingreso: febrero-2004
Ubicación: República Dominicana
Mensajes: 997
Antigüedad: 20 años, 2 meses
Puntos: 7
Respuesta: Aplicar una funcion a un objeto creado dinamicamente

Hola nuevamente @Panino

Me puse a releer el codigo y logre optimizarlo razonablemente asegurandome de depender de un solo objeto, de manera que no se genere cada vez. Aqui completo:

Código HTML:
// Set tooltip objects

var ttTempTitle, ttTempTimer;

var ttObject = document.createElement ('div');
ttObject.style.backgroundColor = '#000';
ttObject.style.fontFamily = 'Helvetica, Arial, sans-serif';
ttObject.style.fontSize = '10px';
ttObject.style.color = '#FFF';
ttObject.style.border = 'solid 1px #FFF';
ttObject.style.padding = '6px';
ttObject.style.position = 'absolute';
ttObject.style.left = '0px';
ttObject.style.top = '0px';
ttObject.style.display = 'none';
ttObject.id = 'lyrtooltip';
ttObject.innerHTML = '';
document.body.appendChild (ttObject);
ttObject.style.zoom = 1;

// Tooltips engine

function setAllTitles ()
{
    var objs = document.getElementsByTagName('*');
    var objsCant = objs.length;
    //
    for (var i = 0; i < objsCant; i++)
    {
	   var obj = objs[i];
	   //
	   if (obj.title)
	   {
		  obj.onmouseover = function () { tooltipOverThis (this); }
		  obj.onmouseout = function () { tooltipOutThis (this); }
	   }
    }
}

function tooltipOverThis (obj)
{
    ttTempTitle = obj.title;
    obj.removeAttribute ('title');
    //
    ttObject.style.display = 'none';
    ttObject.innerHTML = ttTempTitle;
    //
    document.onmousemove = function (evt)
    {
	   ttObject.style.left = ( parseInt (mouseX(evt)) + 15 ) + 'px';
	   ttObject.style.top = ( parseInt (mouseY(evt)) - 5 ) + 'px';
	   ttObject.style.display = 'block';
    }
    //
    clearInterval (ttTempTimer);
    ttTempTimer = setInterval(funcInter,5000);
    function funcInter () { clearInterval (ttTempTimer); tooltipOutThis (obj); }
}
function tooltipOutThis (obj)
{
    clearInterval (ttTempTimer);
    obj.title = ttTempTitle;
    ttObject.style.display = 'none';
    document.onmousemove = null;
}

function mouseX (evt)
{
    if (!evt) evt = window.event;
    if (evt.pageX) return evt.pageX; else if (evt.clientX) return evt.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
    else return 0;
}
function mouseY (evt)
{
    if (!evt) evt = window.event;
    if (evt.pageY) return evt.pageY; else if (evt.clientY) return evt.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
    else return 0;
}
Gracias por el link y por mencionar el tema de los eventos, ya habia leido algo. De todos modos todos estos scripts los estoy implementado en mi propio CM, por lo que me asegurare que los clientes usen navegadores que no sean Explorer cuando me contraten, de todos modos no soy de los que no apoyan el uso de Explorer como veras en mi firma
__________________
JuniHH
- Mi blog
- Mi portafolio
  #10 (permalink)  
Antiguo 10/01/2010, 12:26
Avatar de Tecna  
Fecha de Ingreso: enero-2010
Mensajes: 291
Antigüedad: 14 años, 3 meses
Puntos: 45
Respuesta: Aplicar una funcion a un objeto creado dinamicamente

Buenas,

he simplificado un poco el código que tenias
Código Javascript:
Ver original
  1. var tit = []; //como variable global para poder acceder facilmente
  2.  
  3. function init()
  4. {
  5.     var objs = document.getElementsByTagName('*');
  6.     setAllTitles(objs);
  7. }
  8.  
  9. window.onload = init;
  10.  
  11. function setAllTitles(objs)
  12. {
  13.  
  14. // borramos los titulos, definimos los eventos y creamos el elemento
  15.  
  16.     for (var i = 0; i < objs.length; i++)
  17.     {
  18.         if (objs[i].title)
  19.         {
  20.             var ob = (objs[i]);
  21.             tit[i] = ob.title;
  22.             ob.id = 'elemento-' + i; // me interesa guardar el valor de i
  23.             ob.removeAttribute ('title');
  24.             ob.onmouseover = mouseOver;
  25.             ob.onmouseout = mouseOut;
  26.         } // if
  27.     } // for
  28.  
  29.     document.onmousemove = function (evt){return mouseMove(evt);};
  30.    
  31.     var tt = document.createElement('div');
  32.     tt.className = 'estilos'; // todos los estilos mejor en el css
  33.     tt.id = 'lyrtooltip';  
  34.     document.body.appendChild(tt);
  35.    
  36. }
  37.  
  38. /////////// funciones de los eventos
  39.  
  40. function mouseOver()
  41. {
  42.     var tt = document.getElementById('lyrtooltip');
  43.     tt.style.display = 'block';
  44.     var orden = this.id.substr(9); //recupero el valor de i aqui
  45.     var titulo = tit[orden];    // y asi aqui accedo facilmente al titulo del elemento  
  46.     tt.innerHTML = titulo;
  47. }
  48.  
  49. function mouseOut()
  50. {
  51.     var tt = document.getElementById('lyrtooltip');
  52.     tt.style.display = 'none';
  53. }
  54.  
  55. function mouseMove(evt)
  56. {
  57.     var tt = document.getElementById('lyrtooltip');
  58.     tt.style.left = ( parseInt (mouseX(evt)) + 15 ) + 'px';
  59.     tt.style.top = ( parseInt (mouseY(evt)) - 5 ) + 'px';
  60. }
  61.  
  62. // a partir de aqui esta igual que lo tenias
  63.  
  64. function mouseX(evt)
  65. {
  66.     if (!evt) evt = window.event;
  67.     if (evt.pageX) return evt.pageX; else if (evt.clientX) return evt.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
  68.     else return 0;
  69.  
  70. }
  71.  
  72. function mouseY(evt)
  73. {
  74.     if (!evt) evt = window.event;
  75.     if (evt.pageY) return evt.pageY; else if (evt.clientY) return evt.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
  76.     else return 0;
  77. }
  78.  
  79. //fin

Los estilos los tendrias que asignar mediante css, las funciones de los eventos son independientes, y no hay que añadir nada en el html, con eso ya queda el código mas limpio. Espero que te sirva. Un saludo
  #11 (permalink)  
Antiguo 10/01/2010, 16:34
Avatar de Tecna  
Fecha de Ingreso: enero-2010
Mensajes: 291
Antigüedad: 14 años, 3 meses
Puntos: 45
Respuesta: Aplicar una funcion a un objeto creado dinamicamente

Buenas,

he añadido una función para crear enlaces con algunos datos simulados para poder hacer las pruebas y aplicar los eventos a los elementos creados. También hay que incluir dos líneas en la función init() Y hace falta tener un enlace en el html con id="crear" Son los únicos cambios .

Código Javascript:
Ver original
  1. function init()
  2. {
  3.     var objs = document.getElementsByTagName('*');
  4.    
  5.     var crear = document.getElementById('crear');   // esta linea es nueva
  6.     crear.onclick = function () {crearElemento();};     // esta linea es nueva
  7.    
  8.     setAllTitles(objs);
  9. }
  10.  
  11. //// funcion nueva para crear elementos con sus eventos
  12.  
  13. function crearElemento()
  14. {
  15.     var orden = tit.length;
  16.  
  17.     var nuevo = document.createElement('a');
  18.  
  19.     nuevo.innerHTML = 'enlace-' + orden;
  20.     nuevo.href = '#';
  21.     nuevo.title = 'titulo-' + orden;          // datos de relleno como ejemplo
  22.     nuevo.id = 'elemento-' + orden;
  23.  
  24.     tit[orden] = nuevo.title;
  25.     nuevo.removeAttribute ('title');
  26.    
  27.     document.body.appendChild(nuevo);
  28.  
  29.     //esto es lo importante
  30.     nuevo.onmouseover = mouseOver;
  31.     nuevo.onmouseout = mouseOut;
  32.     document.onmousemove = function (evt){return mouseMove(evt);};
  33. }
  34.  
  35. // fin cambios

Se podría mejorar pero queda bastante limpio. Un saludo

Etiquetas: dinamicamente, funcion, objeto
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 06:10.