1675 votes

Liaison d'événements sur des éléments créés dynamiquement ?

J'ai un bout de code où je boucle sur toutes les boîtes de sélection d'une page et où je lie un fichier de type .hover l'événement pour qu'ils fassent un peu de remaniement avec leur largeur sur mouse on/off .

Cela se produit lorsque la page est prête et fonctionne parfaitement.

Le problème que je rencontre est que toutes les boîtes de sélection que j'ajoute via Ajax ou DOM après la boucle initiale n'auront pas l'événement lié.

J'ai trouvé ce plugin ( Plugin jQuery Live Query ), mais avant d'ajouter un autre 5k à mes pages avec un plugin, je veux voir si quelqu'un connaît un moyen de le faire, soit avec jQuery directement, soit par une autre option.

2544voto

dev.e.loper Points 7181

À partir de jQuery 1.7 vous devez utiliser jQuery.fn.on avec le paramètre du sélecteur rempli :

$(staticAncestors).on(eventName, dynamicChild, function() {});

Explication :

C'est ce qu'on appelle la délégation d'événements et cela fonctionne comme suit. L'événement est attaché à un parent statique ( staticAncestors ) de l'élément qui doit être traité. Ce gestionnaire jQuery est déclenché chaque fois que l'événement se déclenche sur cet élément ou sur l'un des éléments descendants. Le gestionnaire vérifie ensuite si l'élément qui a déclenché l'événement correspond à votre sélecteur ( dynamicChild ). Lorsqu'il y a une correspondance, votre fonction de traitement personnalisée est exécutée.


Avant cela l'approche recommandée était d'utiliser live() :

$(selector).live( eventName, function(){} );

Cependant, live() a été déprécié dans la version 1.7 en faveur de l'option on() et complètement supprimé en 1.9. Le site live() signature :

$(selector).live( eventName, function(){} );

... peut être remplacé par le texte suivant on() signature :

$(document).on( eventName, selector, function(){} );

Par exemple, si votre page créait dynamiquement des éléments avec le nom de classe dosomething vous lieriez l'événement à un parent qui existe déjà (c'est le cœur du problème, vous avez besoin de quelque chose qui existe pour vous lier, ne vous liez pas au contenu dynamique), cela peut être (et c'est l'option la plus simple) document . Mais gardez à l'esprit document peut ne pas être l'option la plus efficace .

$(document).on('mouseover mouseout', '.dosomething', function(){
    // what you want to happen when mouseover and mouseout 
    // occurs on elements that match '.dosomething'
});

Tout parent qui existe au moment où l'événement est lié est parfait. Par exemple

$('.buttons').on('click', 'button', function(){
    // do something here
});

s'appliquerait à

<div class="buttons">
    <!-- <button>s that are generated dynamically and added here -->
</div>

7 votes

Notez que la méthode live ne fonctionne que pour certains événements, et pas d'autres tels que loadedmetadata. (Voir la section caveats dans la documentation).

57 votes

Pour en savoir plus sur la délégation d'événements, cliquez ici : learn.jquery.com/events/event-delegation .

9 votes

Y a-t-il un moyen d'accomplir cela avec du pur javascript/vanilla js ?

421voto

Ronen Rabinovici Points 413

Il y a une bonne explication dans la documentation de jQuery.fn.on .

En bref :

Les gestionnaires d'événements sont liés uniquement aux éléments actuellement sélectionnés ; ils doivent exister sur la page au moment où votre code effectue l'appel à la fonction .on() .

Ainsi, dans l'exemple suivant #dataTable tbody tr doit exister avant que le code ne soit généré.

$("#dataTable tbody tr").on("click", function(event){
    console.log($(this).text());
});

Si du nouveau HTML est injecté dans la page, il est préférable d'utiliser des événements délégués pour attacher un gestionnaire d'événements, comme décrit ci-après.

Événements délégués ont l'avantage de pouvoir traiter des événements provenant d'éléments descendants qui sont ajoutés au document ultérieurement. Par exemple, si le tableau existe, mais que les lignes sont ajoutées dynamiquement à l'aide d'un code, ce qui suit permettra de le gérer :

$("#dataTable tbody").on("click", "tr", function(event){
    console.log($(this).text());
});

Outre leur capacité à gérer des événements sur des éléments descendants qui ne sont pas encore créés, un autre avantage des événements délégués est qu'ils permettent de réduire considérablement les frais généraux lorsque de nombreux éléments doivent être surveillés. Sur une table de données comportant 1 000 lignes dans sa section tbody Le premier exemple de code attache un gestionnaire à 1 000 éléments.

Une approche par délégation d'événements (le deuxième exemple de code) attache un gestionnaire d'événements à un seul élément, l'élément tbody et l'événement ne doit remonter que d'un seul niveau (à partir de l'icône cliquée). tr a tbody ).

Note : Les événements délégués ne fonctionnent pas pour SVG .

13 votes

Ce serait une réponse mieux acceptée parce qu'il serait plus rapide de déléguer à partir de la table spécifique plutôt qu'à partir du document (la zone de recherche serait beaucoup plus petite).

5 votes

@msanjay : Bien que cibler la recherche plus près des éléments soit préférable, la différence de vitesse de recherche est très mineure en pratique. Il faudrait cliquer 50 000 fois par seconde pour s'en rendre compte :)

1 votes

Merci ! Cela a résolu mon problème. Cette simple déclaration était mon problème : "Les gestionnaires d'événements sont liés uniquement aux éléments actuellement sélectionnés ; ils doivent exister sur la page au moment où votre code fait l'appel à...".

140voto

sdimitrijevikj Points 830

Dans la FAQ de JQuery, vous trouverez que vous pouvez utiliser .on() comme ceci

$("body").on("mouseover mouseout", "select", function(e){

  // Do some code here

});

Si vous utilisez une ancienne version de jQuery, vous pouvez utiliser .delegate().

$("body").delegate("select","mouseover mouseout", function(e){

  // .delegate() takes the parameters a bit differently i think , correct me if i am wrong
  // Do some code here

});

De cette façon, tout nouvel élément que vous ajoutez sur votre page reçoit l'événement.

85voto

nickf Points 185423

Vous pouvez ajouter des événements aux objets lorsque vous les créez. Si vous ajoutez les mêmes événements à plusieurs objets à des moments différents, la création d'une fonction nommée peut être la meilleure solution.

var mouseOverHandler = function() {
    // Do stuff
};
var mouseOutHandler = function () {
    // Do stuff
};

$(function() {
    // On the document load, apply to existing elements
    $('select').hover(mouseOverHandler, mouseOutHandler);
});

// This next part would be in the callback from your Ajax call
$("<select></select>")
    .append( /* Your <option>s */ )
    .hover(mouseOverHandler, mouseOutHandler)
    .appendTo( /* Wherever you need the select box */ )
;

44voto

user670265 Points 119

Essayez d'utiliser .live() au lieu de .bind() ; le .live() lieront .hover à votre case à cocher après l'exécution de la requête Ajax.

35 votes

La méthode live() a été déprécié dans la version 1.7 en faveur de on et supprimé dans la version 1.9.

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