jQuery .on() method doesn't see new elements

31,822

Solution 1

You are not using the correct code to get live functionality.

$('#title-items').on('click', 'a', function(e) {
    alert('clicked');
    e.preventDefault();
});
  1. First, select your common ancestor element (#title-items in this example). You can use document here too if you want to handle all a elements.
  2. Pass the event type (on), then the sub selector (a), and then the callback function for the event.

Now, when click events bubble up to #title-items, it will check to see if the element is an a element, and if so, fire the callback.

Solution 2

You want to use event delegation to capture events triggered on events that are present in the DOM at any point in time:

$(<root element>).on('click', 'a', function(e) {
    alert('clicked');
    e.preventDefault();
});

UPDATE - In this example the <root element> is an ancestor of the links to which you are binding that is present in the DOM at the time of binding.

The basic idea is that since we can't attach an event handler to a DOM element not yet in the DOM, we attach the event handler to an ancestor element and wait for the event to bubble up to the ancestor element. Once the event reaches the ancestor event the event.target property is checked to see what was the originally clicked element.

Share:
31,822
cnkt
Author by

cnkt

Updated on July 09, 2022

Comments

  • cnkt
    cnkt almost 2 years

    I'm getting a JSON element and building a list from its items like this:

    getTitles: function(data) {
        data = data || {};
        var list = [];
    
        $.getJSON(
            '/titles',
            data,
            function(data) {
                $.each(data.data, function(key, val) {
                    list.push(
                        '<li><a href="'+ val.href +'">'+ val.title +'</a><span class="count">'+ val.count +'</span></li>'
                    )
                });
    
                $('#title-items').html(list.join(''));
            }
        );
    }
    

    And I'm binding click event for a elements like this:

    $('a').on('click', function(e) {
        alert('clicked');
        e.preventDefault();
    });
    

    Old a elements shows alert but new ones follow URL. Event handler doesn't work for new ones. How can I solve this?

  • user3167101
    user3167101 over 12 years
    @cnkt: Use document for your common ancestor element.
  • Interrobang
    Interrobang over 12 years
    @cnkt: You have to use jQuery >= 1.7 to use .on().
  • Jasper
    Jasper over 12 years
    @Gabe I don't have any idea what the user's HTML structure looks like so this is a demonstration of the general idea. Also .live() is depreciated, so I wouldn't use it in an example.
  • user3167101
    user3167101 over 12 years
    @Jasper: live() was never really appreciated! I think you mean deprecated :P
  • Jasper
    Jasper over 12 years
    @Gabe Doesn't that depend on how nested the elements are?
  • Gabe
    Gabe over 12 years
    @Jasper, yes it would depend on how it's nested, I will remove the downvote, if you edit your answer, since it won't let me until do you do... I just think that could potentially lead to bad practice with this example. The other answer demonstrated a better practice.
  • Jasper
    Jasper over 12 years
    @Gabe That's a good idea, I went more generic than the other answer.
  • gotqn
    gotqn over 11 years
    @alex is this very unpractical? I mean, if I attached this event on the document, then it will triggers this function on every click as you said. :?:?:?
  • Kevin
    Kevin over 11 years
    @gotqn I think you could probably restrict this a little bit so it doesn't attach to every anchor using the <li> ... $('#title-items').on('click', 'li a', function(e) { alert('clicked'); e.preventDefault(); });