web-dev-qa-db-fra.com

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

J'ai un peu de code où je parcourt toutes les cases de sélection d'une page et leur lie un événement .hover afin de faire un peu de tournoiement avec leur largeur sur mouse on/off.

Cela se produit sur la page prête et fonctionne très bien.

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

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

1677
Eli

À partir de jQuery 1.7 , vous devez utiliser jQuery.fn.on :

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

Avant cela , l’approche recommandée consistait à utiliser live() :

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

Cependant, live() était obsolète en 1.7 au profit de on() et complètement supprimé en 1.9. La signature live():

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

... peut être remplacé par le 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 déjà existant (this est le noeud du problème ici, vous avez besoin de quelque chose qui existe pour se lier à, ne vous liez pas au contenu dynamique), cela peut être (et l’option la plus simple) est document. Cependant, gardez à l'esprit que document pourrait 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 existant au moment où l'événement est lié va bien. 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>
_
2084
dev.e.loper

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

En bref:

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

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

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

Si un nouveau code 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.

Les événements délégués ont l'avantage de pouvoir traiter les événements des éléments descendants ajoutés au document ultérieurement. Par exemple, si la table existe, mais que les lignes sont ajoutées de manière dynamique à l'aide de code, ce qui suit le gérera:

_$("#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 leur potentiel de surcharge beaucoup plus faible lorsque de nombreux éléments doivent être surveillés. Sur une table de données contenant 1 000 lignes dans sa variable tbody, le premier exemple de code attache un gestionnaire à 1 000 éléments.

Une approche basée sur des événements délégués (le deuxième exemple de code) attache un gestionnaire d'événements à un seul élément, le tbody, et l'événement n'a besoin que de remonter d'un niveau (de tr à tbody).

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

350
Ronen Rabinovici

Ceci est une solution pure JavaScript sans bibliothèques ni plugins:

document.addEventListener('click', function (e) {
    if (hasClass(e.target, 'bu')) {
        // .bu clicked
        // Do your thing
    } else if (hasClass(e.target, 'test')) {
        // .test clicked
        // Do your other thing
    }
}, false);

hasClass est

function hasClass(elem, className) {
    return elem.className.split(' ').indexOf(className) > -1;
}

Live demo

Le crédit va à Dave et Sime Vidas

En utilisant JS plus moderne, hasClass peut être implémenté comme:

function hasClass(elem, className) {
    return elem.classList.contains(className);
}
195
Ram Patra

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, vous pouvez créer une fonction nommée.

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 */ )
;
68
nickf

Vous pouvez simplement envelopper votre appel de liaison d'événement dans une fonction, puis l'invoquer deux fois: une fois sur le document prêt et une fois après votre événement qui ajoute les nouveaux éléments DOM. Si vous faites cela, vous voudrez éviter de lier deux fois le même événement aux éléments existants. Vous devrez donc dissocier les événements existants ou (mieux) ne lier que les éléments DOM nouvellement créés. Le code ressemblerait à ceci:

function addCallbacks(eles){
    eles.hover(function(){alert("gotcha!")});
}

$(document).ready(function(){
    addCallbacks($(".myEles"))
});

// ... add elements ...
addCallbacks($(".myNewElements"))
47
Greg Borenstein

Essayez d'utiliser .live() au lieu de .bind(); la .live() liera .hover à votre case à cocher après l'exécution de la demande Ajax.

40
user670265

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

Elément unique:

$(document.body).on('click','.element', function(e) {  });

Élément enfant:

 $(document.body).on('click','.element *', function(e) {  });

Remarquez le * ajouté. Un événement sera déclenché pour tous les enfants de cet élément.

J'ai remarqué que:

$(document.body).on('click','.#element_id > element', function(e) {  });

Ça ne marche plus, mais ça marchait avant. J'utilise jQuery de Google CDN , mais je ne sais pas s'ils l'ont changé.

24
MadeInDreams

Vous pouvez utiliser la méthode live () pour lier des éléments (même nouvellement créés) à des événements et à des gestionnaires, comme l'événement onclick.

Voici un exemple de code que j'ai écrit, dans lequel vous pouvez voir comment la méthode live () lie des éléments choisis, même nouvellement créés, à des événements:

<!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>Untitled Document</title>
    </head>

    <body>
        <script src="http://code.jquery.com/jquery-latest.js"></script>
        <script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.16/jquery-ui.min.js"></script>

        <input type="button" id="theButton" value="Click" />
        <script type="text/javascript">
            $(document).ready(function()
                {
                    $('.FOO').live("click", function (){alert("It Works!")});
                    var $dialog = $('<div></div>').html('<div id="container"><input type ="button" id="CUSTOM" value="click"/>This dialog will show every time!</div>').dialog({
                                                                                                         autoOpen: false,
                                                                                                         tite: 'Basic Dialog'
                                                                                                     });
                    $('#theButton').click(function()
                    {
                        $dialog.dialog('open');
                        return('false');
                    });
                    $('#CUSTOM').click(function(){
                        //$('#container').append('<input type="button" value="clickmee" class="FOO" /></br>');
                        var button = document.createElement("input");
                        button.setAttribute('class','FOO');
                        button.setAttribute('type','button');
                        button.setAttribute('value','CLICKMEE');
                        $('#container').append(button);
                    });
                    /* $('#FOO').click(function(){
                                                     alert("It Works!");
                                                 }); */
            });
        </script>
    </body>
</html>
23
Fazi

Je préfère utiliser le sélecteur et je l'applique sur le document.

Cela se lie au document et sera applicable aux éléments qui seront rendus après le chargement de la page.

Par exemple:

$(document).on("click", $(selector), function() {
    // Your code here
});
19
Vatsal

Une autre solution consiste à ajouter l'écouteur lors de la création de l'élément. Au lieu de mettre l'auditeur dans le corps, vous placez l'auditeur dans l'élément au moment où vous le créez:

var myElement = $('<button/>', {
    text: 'Go to Google!'
});

myElement.bind( 'click', goToGoogle);
myElement.append('body');


function goToGoogle(event){
    window.location.replace("http://www.google.com");
}
18
Martin Da Rosa

Vous pouvez attacher un événement à un élément lorsque créé dynamiquement à l'aide de jQuery(html, attributes) .

À partir de jQuery 1.8 , toute méthode d'instance jQuery (une méthode de jQuery.fn) peut être utilisée comme propriété de l'objet transmis à la seconde paramètre:

function handleDynamicElementEvent(event) {
  console.log(event.type, this.value)
}
// create and attach event to dynamic element
jQuery("<select>", {
    html: $.map(Array(3), function(_, index) {
      return new Option(index, index)
    }),
    on: {
      change: handleDynamicElementEvent
    }
  })
  .appendTo("body");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
13
guest271314

Prenez note de la classe "MAIN" dans laquelle l'élément est placé, par exemple,

<div class="container">
     <ul class="select">
         <li> First</li>
         <li>Second</li>
    </ul>
</div>

Dans le scénario ci-dessus, l'objet MAIN que jQuery va surveiller est "conteneur".

Ensuite, vous aurez essentiellement des noms d'éléments sous conteneur tels que ul, li et select:

$(document).ready(function(e) {
    $('.container').on( 'click',".select", function(e) {
        alert("CLICKED");
    });
 });
13
Aslan Kaya

vous pourriez utiliser

$('.buttons').on('click', 'button', function(){
    // your magic goes here
});

ou

$('.buttons').delegate('button', 'click', function() {
    // your magic goes here
});

ces deux méthodes sont équivalentes mais ont un ordre de paramètres différent.

voir: événement de délégué jQuery

12
Mensur Grišević

Essayez comme ça -

$(document).on( 'click', '.click-activity', function () { ... });
10
Rohit Suthar

Voici pourquoi les éléments créés dynamiquement ne répondent pas aux clics:

var body = $("body");
var btns = $("button");
var btnB = $("<button>B</button>");
// `<button>B</button>` is not yet in the document.
// Thus, `$("button")` gives `[<button>A</button>]`.
// Only `<button>A</button>` gets a click listener.
btns.on("click", function () {
  console.log(this);
});
// Too late for `<button>B</button>`...
body.append(btnB);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>

Pour contourner le problème, vous devez écouter tous les clics et vérifier l'élément source:

var body = $("body");
var btnB = $("<button>B</button>");
var btnC = $("<button>C</button>");
// Listen to all clicks and
// check if the source element
// is a `<button></button>`.
body.on("click", function (ev) {
  if ($(ev.target).is("button")) {
    console.log(ev.target);
  }
});
// Now you can add any number
// of `<button></button>`.
body.append(btnB);
body.append(btnC);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>

Cela s'appelle "Délégation d'événements". Bonne nouvelle, c'est une fonctionnalité intégrée à jQuery :-)

var i = 11;
var body = $("body");
body.on("click", "button", function () {
  var letter = (i++).toString(36).toUpperCase();
  body.append($("<button>" + letter + "</button>"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>
10
leaf

Ceci est effectué par délégation d'événement . Event sera lié à un élément wrapper-class mais sera délégué à un élément sélector-class. Voilà comment cela fonctionne.

$('.wrapper-class').on("click", '.selector-class', function() {
    // Your code here
});

Remarque:

l'élément wrapper-class peut être n'importe quoi ex. document, corps ou votre wrapper. Le wrapper devrait déjà exister. Cependant, selector ne doit pas nécessairement être présent au moment du chargement de la page. Cela peut arriver plus tard et l'événement sera lié sur selectorsans échec.

9
Asif J

Tout p qui n'existe pas au moment où l'événement est lié et si votre page était création dynamique d'éléments avec le nom de la classe bouton vous lieriez le événement à un parent qui existe déjà

$(document).ready(function(){
  //Particular Parent chield click
  $(".buttons").on("click","button",function(){
    alert("Clicked");
  });  
  
  //Dynamic event bind on button class  
  $(document).on("click",".button",function(){
    alert("Dymamic Clicked");
  });
  $("input").addClass("button");  
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="buttons">
  <input type="button" value="1">
  <button>2</button>
  <input type="text">
  <button>3</button>  
  <input type="button" value="5">  
  </div>
<button>6</button>
8
Ankit Kathiriya

Lier l'événement à un parent qui existe déjà:

$(document).on("click", "selector", function() {
    // Your code here
});
5
truongnm

Utilisez la méthode .on() de jQuery http://api.jquery.com/on/ pour attacher des gestionnaires d’événements à l’élément actif.

Également à partir de la version 1.9, la méthode .live() est supprimée.

4
Kalpesh Patel

Une autre solution flexible pour créer des éléments et lier des événements ( source )

// creating a dynamic element (container div)
var $div = $("<div>", {id: 'myid1', class: 'myclass'});

//creating a dynamic button
 var $btn = $("<button>", { type: 'button', text: 'Click me', class: 'btn' });

// binding the event
 $btn.click(function () { //for mouseover--> $btn.on('mouseover', function () {
    console.log('clicked');
 });

// append dynamic button to the dynamic container
$div.append($btn);

// add the dynamically created element(s) to a static element
$("#box").append($div);

Remarque: Ceci créera une instance de gestionnaire d'événements pour chaque élément (peut affecter les performances lorsqu'il est utilisé dans des boucles).

2
Prasad De Silva

Je préfère que les écouteurs d'événements soient déployés de manière modulaire plutôt que de scripter un écouteur d'événements de niveau document. Donc, j'aime bien ci-dessous. Remarque: vous ne pouvez pas sursouscrire un élément avec le même écouteur d'événement, alors ne vous inquiétez pas si vous attachez un auditeur plus d'une fois - un seul stick.

var iterations = 4;
var button;
var body = document.querySelector("body");

for (var i = 0; i < iterations; i++) {
    button = document.createElement("button");
    button.classList.add("my-button");
    button.appendChild(document.createTextNode(i));
    button.addEventListener("click", myButtonWasClicked);
    body.appendChild(button);
}

function myButtonWasClicked(e) {
    console.log(e.target); //access to this specific button
}
2
Ron Royston