jQuery как привязать событие onclick к динамически добавляемому HTML-элементу

Я хочу привязать событие onclick к элементу, который я вставляю динамически с помощью jQuery

но он никогда не запускает привязанную функцию. Я был бы рад, если бы вы могли указать, почему этот пример не работает и как я могу заставить его работать правильно:

<!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: я отредактировал пример, чтобы содержать два элемента, в которые вставлен метод. в этом случае alert() вызова никогда не выполняется. (спасибо @Daff за указание на это в комментарий)

9 ответов


первая проблема заключается в том, что при вызове append в наборе jQuery с более чем одним элементом создается клон элемента для добавления для каждого и, таким образом, присоединенный наблюдатель событий теряется.

альтернативным способом сделать это было бы создать ссылку для каждого элемента:

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

другой потенциальной проблемой может быть то, что наблюдатель событий присоединен до добавления элемента в DOM. Я не уверен, что это что-то говорит, но я думаю, что поведение можно считать неопределенным. Более солидным подходом, вероятно, было бы:

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

все эти методы устарели. Вы должны использовать on метод для решения вашей проблемы.

Если вы хотите нацелить динамически добавленный элемент, вам придется использовать

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

это заменить устаревший .live() метод.


Как насчет метода Live?

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

тем не менее, то, что вы сделали, похоже, должно сработать. Есть следующий пост это выглядит довольно похоже.


немного поздно на вечеринку, но я думал, что попытаюсь прояснить некоторые распространенные заблуждения в обработчиках событий jQuery. По состоянию на jQuery 1.7,.on() следует использовать вместо устаревшей .live(), чтобы делегировать обработчики событий элементам, которые динамически создаются в любой момент после назначения обработчика событий.

тем не менее, это не просто переключение live на on потому что синтаксис немного отличается:

новый способ (например, 1):

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

});

устаревший метод (Пример 2):

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

});

как показано выше, есть разница. Поворот .on() на самом деле можно назвать как .live(), передав селектор самой функции jQuery:

Пример 3:

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

});
, без $(document) как и в Примере 1, Пример 3 не будет работать для динамически созданных элементов. Пример 3 абсолютно хорош, если вам не нужна динамика делегация.

должны $(документ).на() на все?

это будет работать, но если вам не нужно динамическое делегирование, было бы более целесообразно использовать пример 3, потому что Пример 1 требует немного больше работы от браузера. Не будет никакого реального влияния на производительность, но имеет смысл использовать наиболее подходящий метод для вашего использования.

должны .на() Вместо .нажмите (), если нет динамического делегирование необходимо?

не обязательно. Ниже приведен только ярлык для примера 3:

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

});

вышеизложенное совершенно справедливо, и поэтому это действительно вопрос личных предпочтений относительно того, какой метод используется, когда не требуется динамическое делегирование.

ссылки:


рассмотрим следующий пример:

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

Он будет работать, потому что вы приложите его к каждому конкретному элементу. Вот почему вам нужно-после добавления ссылки на DOM - найти способ явно выбрать добавленный элемент в качестве элемента JQuery в DOM и привязать к нему событие click.

лучшим способом, вероятно , будет - как было предложено-привязать его к определенному классу с помощью метода live.


Я считаю, что хороший способ это сделать:

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

возможно и иногда необходимо создать событие click вместе с элементом. Это, например, когда привязка на основе селектора не является опцией. Ключевая часть состоит в том, чтобы избежать проблемы, что Тобиас говорил об использовании .replaceWith() на одном элементе. Обратите внимание, что это всего лишь доказательство концепции.

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

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

<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>    
<script>
    $(document).ready(function(){
        $(document).on('click', '.close', function(){
            var rowid='row'+this.id;
            var sl = '#tblData tr[id='+rowid+']';
            console.log(sl);
            $(sl).remove();
        });
        $("#addrow").click(function(){
            var row='';
            for(var i=0;i<10;i++){
                row=i;
                row='<tr id=row'+i+'>'
                    +   '<td>'+i+'</td>'
                    +   '<td>ID'+i+'</td>'
                    +   '<td>NAME'+i+'</td>'
                    +   '<td><input class=close type=button id='+i+' value=X></td>'
                    +'</tr>';
                console.log(row);
                $('#tblData tr:last').after(row);
            }
        });
    });

</script>
</head>
  <body>
    <br/><input type="button" id="addrow" value="Create Table"/>
    <table id="tblData" border="1" width="40%">
        <thead>
        <tr>
            <th>Sr</th>
            <th>ID</th>
            <th>Name</th>
            <th>Delete</th>
        </tr>
        </thead>
    </table>
    </body>
 </html>