Marcos
Marcos

Reputation: 69

Click event with DOM dynamically updates

I'm playing with a few samples to learn jQuery. I made an example to add items to a list when user clicks an add button and display items list when they click in any item of the list:

The code:

HTML

<div id="sample"></div>
    <a id="add" href="#">Add</a>
    <ul id="list">
        <li>old item</li>
        <li>old item</li>
        <li>old item</li>
    </ul>
</div>

jQuery

var $itemsList = jQuery('#list li');

jQuery('#add').click(function(e){
    e.preventDefault();
    jQuery('#list').append('<li>new item</li>');
    $itemsList = jQuery('#list li');
});

$itemsList.click(function(e){
    e.preventDefault();
    console.log('there are ' + $itemsList.length + ' items');
    $itemsList.each(function(){
        console.log(jQuery(this).text());
    });
});

The problem:

If the user clicks in old items, the console displays all items (old and new), but if the user clicks in new items, created by clicking the add button, they are not being displayed. I'm assuming that the event click was asigned to $itemsList, and this object only refers to items created when script loads but not with successive created items.

Any advice, sugestions?

Upvotes: 2

Views: 209

Answers (3)

Didier Ghys
Didier Ghys

Reputation: 30666

When doing this $itemsList.click(...) you bind an event handler to the 'click' event, but even if you re-select the list items in the 'Add' event handler, new items are not binded automatically.

You have to use event delegation for you click event to binded to elements added dynamically.

$('#list').on('click', 'li', clickHandler);

Doing this can be translated into: delegate the 'click' event on the element #list, and restrain the event handling to li elements only (second parameter).

The .on() method was added in jquery 1.7. In case you use a prior version of the library, use .delegate().

Note: forget about .live() which is deprecated.

Documentation on .on() and .delegate()

Upvotes: 1

Oyeme
Oyeme

Reputation: 11225

var $itemsList = jQuery('#list');

jQuery('#add').click(function(e){
    e.preventDefault();
    jQuery('#list').append('<li>new item</li>');
    $itemsList = jQuery('#list li');
});

$itemsList.on("click","li",function(e){
    e.preventDefault();
    console.log('there are ' + $itemsList.length + ' items');
    $itemsList.each(function(){
        console.log(jQuery(this).text());
    });
});

jQuery 1.7.1

ON() -> live() or delegate()

Description: Attach an event handler for all elements which match the current selector, now and in the future.

Upvotes: 2

Rory McCrossan
Rory McCrossan

Reputation: 337626

Because you are appending new items to the DOM, you need to use a different method to assign them handlers, as click() is only used for DOM elements available to jQuery on load.

Instead, use delegate() to add the handlers:

var $itemsList = jQuery('#list li');

jQuery('#add').click(function(e){
    e.preventDefault();
    jQuery('#list').append('<li>new item</li>');
    $itemsList = jQuery('#list li');
});

$("#list").delegate("LI", "click", function(e){
    e.preventDefault();
    $("#total").text('there are ' + $itemsList.length + ' items');
    $itemsList.each(function(){
        console.log(jQuery(this).text());
    });
});

Example fiddle here

Or, if you're using jQuery 1.7+ you can use on() instead of delegate(), but their functionality essentially the same in this scenario.

Upvotes: 1

Related Questions