web-dev-qa-db-fra.com

jQuery comment lier un événement onclick à un élément HTML ajouté dynamiquement

Je souhaite lier un événement onclick à un élément que j'insère de manière dynamique avec jQuery

Mais il n'exécute jamais la fonction liée. Je serais heureux si vous pouviez expliquer pourquoi cet exemple ne fonctionne pas et comment je peux le faire fonctionner correctement:

<!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" xml:lang="da" lang="da">
        <head>
          <title>test of click binding</title>

<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
          <script type="text/javascript">


        jQuery(function(){
          close_link = $('<a class="" href="#">Click here to see an alert</a>');
          close_link.bind("click", function(){
            alert('hello from binded function call');
            //do stuff here...
          });
  
          $('.add_to_this').append(close_link);
        });
          </script>
        </head>
        <body>
          <h1 >Test of click binding</h1>
          <p>problem: to bind a click event to an element I append via JQuery.</p>

          <div class="add_to_this">
            <p>The link is created, then added here below:</p>
          </div>

          <div class="add_to_this">
            <p>Another is added here below:</p>
          </div>


        </body>
        </html>

EDIT: j'ai modifié l'exemple pour qu'il contienne deux éléments dans lesquels la méthode est insérée. Dans ce cas, l'appel alert() n'est jamais exécuté. (merci à @Daff de l'avoir signalé dans un commentaire)

122

Le premier problème est que, lorsque vous appelez append sur un ensemble jQuery avec plusieurs éléments, un clone de l'élément à ajouter est créé pour chacun d'eux et l'observateur d'événements attaché est donc perdu.

Une autre façon de le faire serait de créer le lien pour chaque élément:

function handler() { alert('hello'); }
$('.add_to_this').append(function() {
  return $('<a>Click here</a>').click(handler);
})

Un autre problème potentiel pourrait être que l'observateur d'événement est associé avant que l'élément ait été ajouté au DOM. Je ne sais pas si cela a quelque chose à dire, mais je pense que le comportement pourrait être considéré comme indéterminé. Une approche plus solide serait probablement:

function handler() { alert('hello'); }
$('.add_to_this').each(function() {
  var link = $('<a>Click here</a>');
  $(this).append(link);
  link.click(handler);
});
59
Tobias

Toutes ces méthodes sont déconseillées. Vous devez utiliser la méthode on pour résoudre votre problème.

Si vous souhaitez cibler un élément ajouté dynamiquement, vous devez utiliser

$(document).on('click', selector-to-your-element , function() {
     //code here ....
});

cela remplace la méthode obsolète .live().

279
aM1Ne

Qu'en est-il de la méthode Live?

$('.add_to_this a').live('click', function() {
    alert('hello from binded function call');
});

Pourtant, ce que vous avez fait semble que cela devrait fonctionner. Il y a n autre post qui a l'air assez similaire.

51
Brother Erryn

Un peu tard pour la fête, mais je pensais que j'essaierais de dissiper certaines idées fausses courantes dans les gestionnaires d’événements jQuery. A partir de jQuery 1.7, .on() doit être utilisé à la place de .live() (obsolète), pour déléguer des gestionnaires d'événements à des éléments créés dynamiquement à tout moment après l'affectation du gestionnaire d'événements.

Cela dit, il ne s’agit pas simplement de passer de live à on car la syntaxe est légèrement différente:

Nouvelle méthode (exemple 1):

$(document).on('click', '#someting', function(){

});

Méthode obsolète (exemple 2):

$('#something').live(function(){

});

Comme indiqué ci-dessus, il y a une différence. La torsion est .on() peut en fait s'appeler similaire à .live(), en passant le sélecteur à la fonction jQuery elle-même:

Exemple 3:

$('#something').on('click', function(){

});

Cependant, sans utiliser $(document) comme dans l'exemple 1, l'exemple 3 ne fonctionnera pas pour les éléments créés dynamiquement. L'exemple 3 convient parfaitement si vous n'avez pas besoin de la délégation dynamique.

$ (Document) .on () doit-il être utilisé pour tout?

Cela fonctionnera, mais si vous n'avez pas besoin de la délégation dynamique, il serait plus approprié d'utiliser l'exemple 3, car l'exemple 1 nécessite un peu plus de travail de la part du navigateur. Il n'y aura pas de réel impact sur les performances, mais il est logique d'utiliser la méthode la plus appropriée.

Est-ce que .on () devrait être utilisé à la place de .click () si aucune délégation dynamique n'est nécessaire?

Pas nécessairement. Voici un raccourci pour l'exemple 3:

$('#something').click(function(){

});

Ce qui précède est parfaitement valide. Il est donc essentiel de choisir la méthode à utiliser lorsque aucune délégation dynamique n’est requise.

Références:

18
MrCode

Considère ceci:

jQuery(function(){
  var close_link = $('<a class="" href="#">Click here to see an alert</a>');
      $('.add_to_this').append(close_link);
      $('.add_to_this').children().each(function()
      {
        $(this).click(function() {
            alert('hello from binded function call');
            //do stuff here...
        });
      });
});

Cela fonctionnera parce que vous l'attachez à chaque élément spécifique. C'est pourquoi vous devez, après avoir ajouté votre lien dans le DOM, trouver un moyen de sélectionner explicitement votre élément ajouté en tant qu'élément JQuery dans le DOM et d'y associer l'événement click.

Le meilleur moyen sera probablement - comme suggéré - de le lier à une classe spécifique via la méthode live.

1
Daff

Il est possible et parfois nécessaire de créer l'événement click avec l'élément. C'est par exemple le cas où la liaison basée sur un sélecteur n'est pas une option. L'essentiel est d'éviter le problème dont Tobias parlait en utilisant .replaceWith() sur un seul élément. Notez que ceci est juste une preuve de concept.

<script>
    // This simulates the object to handle
    var staticObj = [
        { ID: '1', Name: 'Foo' },
        { ID: '2', Name: 'Foo' },
        { ID: '3', Name: 'Foo' }
    ];
    staticObj[1].children = [
        { ID: 'a', Name: 'Bar' },
        { ID: 'b', Name: 'Bar' },
        { ID: 'c', Name: 'Bar' }
    ];
    staticObj[1].children[1].children = [
        { ID: 'x', Name: 'Baz' },
        { ID: 'y', Name: 'Baz' }
    ];

    // This is the object-to-html-element function handler with recursion
    var handleItem = function( item ) {
        var ul, li = $("<li>" + item.ID + " " + item.Name + "</li>");

        if(typeof item.children !== 'undefined') {
            ul = $("<ul />");
            for (var i = 0; i < item.children.length; i++) {
                ul.append(handleItem(item.children[i]));
            }
            li.append(ul);
        }

        // This click handler actually does work
        li.click(function(e) {
            alert(item.Name);
            e.stopPropagation();
        });
        return li;
    };

    // Wait for the dom instead of an ajax call or whatever
    $(function() {
        var ul = $("<ul />");

        for (var i = 0; i < staticObj.length; i++) {
            ul.append(handleItem(staticObj[i]));
        }

        // Here; this works.
        $('#something').replaceWith(ul);
    });
</script>
<div id="something">Magical ponies ♥</div>
0
Nenotlep
    function load_tpl(selected=""){
        $("#load_tpl").empty();
        for(x in ds_tpl){
            $("#load_tpl").append('<li><a id="'+ds_tpl[x]+'" href="#" >'+ds_tpl[x]+'</a></li>');
        }
        $.each($("#load_tpl a"),function(){
            $(this).on("click",function(e){
                alert(e.target.id);
            });
        });
    }
0
tanthuc

Je crois la bonne façon de faire:

$('#id').append('<a id="#subid" href="#">...</a>');
$('#subid').click( close_link );
0
yogsototh