172 votes

Est-il possible d'ajouter un élément à innerHTML sans détruire les fonctions onclick des descendants ?

Dans l'exemple de code suivant, j'attache un gestionnaire onclick au span contenant le texte "foo". Le gestionnaire est une fonction anonyme qui fait apparaître un alert().

Cependant, si j'ajoute le texte innerHTML du nœud parent, ce gestionnaire onclick est détruit : cliquer sur "foo" ne fait pas apparaître la boîte d'alerte.

Est-ce que ça peut être réparé ?

<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>

160voto

Ben Blank Points 21786

Malheureusement, l'affectation à innerHTML entraîne la destruction de tous les éléments enfants, même si vous essayez d'ajouter des éléments. Si vous souhaitez préserver les nœuds enfants (et leurs gestionnaires d'événements), vous devrez utiliser la méthode suivante Fonctions DOM :

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

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

Edit : La solution de Bob, d'après les commentaires. Publie ta réponse, Bob ! Soyez crédité de votre réponse. :-)

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);
    }
}

4voto

rocketsarefast Points 1167

Aujourd'hui, nous sommes en 2012, et jQuery dispose de fonctions append et prepend qui font exactement cela, ajouter du contenu sans affecter le contenu actuel. Très utile.

3voto

Eneroth3 Points 11

J'ai créé mon balisage pour qu'il soit inséré sous la forme d'une chaîne de caractères, car c'est moins de code et plus facile à lire que de travailler avec le truc fantaisiste du dom.

Ensuite, j'en ai fait le innerHTML d'un élément temporaire afin de pouvoir prendre le seul et unique enfant de cet élément et l'attacher au corps.

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

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

1voto

Cargowire Points 633

Par ailleurs, si vous utilisez une bibliothèque javascript telle que jquery (v1.3) pour manipuler les domaines, vous pouvez utiliser des événements en direct en mettant en place un gestionnaire comme celui-ci :

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

et il sera appliqué à ce sélecteur à tout moment pendant toute sorte de manipulation de jquery. Pour les événements en direct, voir : docs.jquery.com/events/live pour la manipulation de jquery voir : docs.jquery.com/manipulation

0voto

Yes - that Jake. Points 9184

La perte des gestionnaires d'événements est, selon moi, un bug dans la façon dont Javascript gère le DOM. Pour éviter ce comportement, vous pouvez ajouter ce qui suit :

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
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X