2009-02-27 28 views
64

En el siguiente código de ejemplo, adjunto un controlador de eventos onclick al tramo que contiene el texto "foo". El controlador es una función anónima que muestra una alerta().¿Es posible añadir a innerHTML sin destruir los detectores de eventos de los descendientes?

Sin embargo, si asigno el nodo principal innerHTML, este controlador de eventos onclick se destruye, haciendo clic en "foo" no aparece el cuadro de alerta.

¿Es esto solucionable?

<html> 
<head> 
<script type="text/javascript"> 

    function start() { 
    myspan = document.getElementById("myspan"); 
    myspan.onclick = function() { alert ("hi"); }; 

    mydiv = document.getElementById("mydiv"); 
    mydiv.innerHTML += "bar"; 
    } 

</script> 
</head> 

<body onload="start()"> 
    <div id="mydiv" style="border: solid red 2px"> 
    <span id="myspan">foo</span> 
    </div> 
</body> 

</html> 
+0

Esta pregunta se relaciona con el problema 'Agregar nuevos campos a un formulario borra la entrada del usuario'. La respuesta seleccionada corrige muy bien estos dos problemas. – MattT

Respuesta

88

Por desgracia, la asignación a innerHTML provoca la destrucción de todos los elementos secundarios, incluso si usted está tratando de anexar. Si desea conservar los nodos hijos (y sus controladores de eventos), tendrá que utilizar :

function start() { 
    var myspan = document.getElementById("myspan"); 
    myspan.onclick = function() { alert ("hi"); }; 

    var mydiv = document.getElementById("mydiv"); 
    mydiv.appendChild(document.createTextNode("bar")); 
} 

Editar: solución de Bob, a partir de los comentarios. Publica tu respuesta, Bob! Obtener crédito por eso. :-)

function start() { 
    var myspan = document.getElementById("myspan"); 
    myspan.onclick = function() { alert ("hi"); }; 

    var mydiv = document.getElementById("mydiv"); 
    var newcontent = document.createElement('div'); 
    newcontent.innerHTML = "bar"; 

    while (newcontent.firstChild) { 
     mydiv.appendChild(newcontent.firstChild); 
    } 
} 
+0

¿Existe un sustituto que pueda agregar un blob de HTML arbitrario? – mike

+43

newcontent = document.createElement ('div'); newcontent.innerHTML = arbitrary_blob; while (newcontent.firstChild) mydiv.appendChild (newcontent.firstChild); – bobince

+0

¡Agradable, Bob! Si publica eso como una respuesta bien formateada, lo seleccionaré. – mike

1

Losing event handlers es, IMO, un error en la forma en que Javascript maneja el DOM. Para evitar este comportamiento, puede agregar lo siguiente:

function start() { 
    myspan = document.getElementById("myspan"); 
    myspan.onclick = function() { alert ("hi"); }; 

    mydiv = document.getElementById("mydiv"); 
    clickHandler = mydiv.onclick; // add 
    mydiv.innerHTML += "bar"; 
    mydiv.onclick = clickHandler; // add 
} 
+2

No considero esto un error. Reemplazar un elemento significa que lo reemplaza completamente. No debería heredar lo que estaba allí antes. –

+0

Pero no quiero reemplazar un elemento; Solo quiero agregar nuevos al padre. – mike

+0

Si estuviera reemplazando el elemento, estaría de acuerdo, @Diodeus. No es el .innerHTML el que tiene el controlador de eventos, sino el padre de .innerHtml. –

3

Como asside ligera (pero relacionados), si se utiliza una biblioteca de Javascript como jQuery (v1.3) para hacer su manipulación del DOM se puede hacer uso de eventos en directo mediante el cual se configura un controlador como:

$("#myspan").live("click", function(){ 
    alert('hi'); 
}); 

y se va a aplicar a ese selector en todo momento durante cualquier tipo de manipulación jQuery. Para ver eventos en vivo, consulte: docs.jquery.com/events/live para la manipulación de jquery. Vea: docs.jquery.com/manipulation

-3

Soy un programador perezoso. No uso DOM porque parece una mecanografía extra. Para mí, cuanto menos código, mejor. Así es como yo añadiría "barra" sin sustituir "foo":

function start(){ 
var innermyspan = document.getElementById("myspan").innerHTML; 
document.getElementById("myspan").innerHTML=innermyspan+"bar"; 
} 
+12

Esta pregunta es preguntar cómo hacer esto sin perder controladores de eventos, por lo que su respuesta no es relevante, y por cierto esto es lo que + = hace, que es mucho más corto – wlf

+0

Es divertido que en esta respuesta completamente incorrecta que cita evitar escribir extra como justificación, aproximadamente la mitad del código es redundante. – JLRishe

4

Ahora bien, es de 2012, y jQuery tiene añadir y anteponer las funciones que hacen exactamente esto, agregar contenido sin afectar el contenido actual. Muy útil.

+4

['.insertAdjacentHTML'] (https://developer.mozilla.org/es/DOM/element.insertAdjacentHTML) ha estado presente desde IE4 – Esailija

+1

@Esailija, eso no funciona en Firefox. – Tynach

+0

@Tynach sí, es su sitio de JavaScript que lo documenta mejor: https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML –

2

Creé mi marcado para insertarlo como una cadena ya que es menos código y más fácil de leer que trabajar con las cosas de fantasía.

Luego lo hice en el interior HTML de un elemento temporal solo para poder tomar el único hijo de ese elemento y unirlo al cuerpo.

var html = '<div>'; 
html += 'Hello div!'; 
html += '</div>'; 

var tempElement = document.createElement('div'); 
tempElement.innerHTML = html; 
document.getElementsByTagName('body')[0].appendChild(tempElement.firstChild); 
0

Se podía hacerlo de esta manera:

var anchors = document.getElementsByTagName('a'); 
var index_a = 0; 
var uls = document.getElementsByTagName('UL'); 
window.onload=function()   {alert(anchors.length);}; 
for(var i=0 ; i<uls.length; i++) 
{ 
    lis = uls[i].getElementsByTagName('LI'); 
    for(var j=0 ;j<lis.length;j++) 
    { 
     var first = lis[j].innerHTML; 
     string = "<img src=\"http://g.etfv.co/" + anchors[index_a++] + 
      "\" width=\"32\" 
     height=\"32\" /> " + first; 
     lis[j].innerHTML = string; 
    } 
} 
17

Usando .insertAdjacentHTML() conserva detectores de eventos, y is supported by all major browsers. Es un reemplazo simple de una línea para .innerHTML.

var html_to_insert = "<p>New paragraph</p>"; 

// with .innerHTML, destroys event listeners 
document.getElementById('mydiv').innerHTML += html_to_insert; 

// with .insertAdjacentHTML, preserves event listeners 
document.getElementById('mydiv').insertAdjacentHTML('beforeend', html_to_insert); 

El argumento 'beforeend' especifica en qué lugar del elemento a insertar el contenido HTML. Las opciones son 'beforebegin', 'afterbegin', 'beforeend' y 'afterend'.Sus ubicaciones correspondientes son:

<!-- beforebegin --> 
<div id="mydiv"> 
    <!-- afterbegin --> 
    <p>Existing content in #mydiv</p> 
    <!-- beforeend --> 
</div> 
<!-- afterend --> 
+0

¡Muy interesante! Gracias por esta solución :) –

+0

Mucho la mejor solución, IMO – Velojet

Cuestiones relacionadas