Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery selector doesn't update after dynamically adding new elements

My selector is:

$('section#attendance input:last')

However, I append another input to section#attendance. I want the selector to now select that element (as it should, because of the :last. However, for some reason, it doesn't, and I'm not too sure why?

Here's my full code:

$('section#attendance input:last').keydown(function(e) {
        if (e.which == 9)
        {
            var $this = $(this);
            var num = parseInt($this.attr('name').match(/\d+(,\d+)?/)[0]) + 1;
            $this.parent().append('<input type="text" name="attendance[' + num +']" value="Name and Position" class="medium" />');
        }
    });

New Code:

    $("section#attendance").on("keydown", "input:last", function(e) {
    if (e.which == 9) {
        var $this = $(this);
        var num = parseInt($this.attr('name').match(/\d+(,\d+)?/)[0]) + 1;
        $this.after('<input type="text" name="attendance[' + num +']" value="Name and Position" class="medium" />');
    }
});

EDIT: The issue seems to be on the 'input:last', as it works if I just use input. Also, if I add class 'last' to the last element, it works when I use 'input.last' as a selector.

like image 704
chintanparikh Avatar asked Feb 19 '12 03:02

chintanparikh


1 Answers

Depending upon what jQuery version you are using, you should use either .delegate() (before jQuery 1.7) or .on() (jQuery 1.7+) to have delegated event handling that will handle events for elements that are added dynamically. Note .live() has been deprecated from all versions of jQuery so it should no longer be used.

Using .on(), you can use this:

$("#attendance").on("keydown", "input:last", function(e) {
    if (e.which == 9) {
        var $this = $(this);
        var num = parseInt($this.attr('name').match(/\d+(,\d+)?/)[0]) + 1;
        $this.parent().append('<input type="text" name="attendance[' + num +']" value="Name and Position" class="medium" />');
    }
});

Using .delegate() would be similar (except the arguments are in a different order). You can see both of them in the jQuery doc .delegate() and .on().

Delegated event handling works using the "bubbling" capability of some javascript events. This allows you to attach an event handler to a parent object (that does not come and go) and have it look at each event that "bubbles" up to it from a child, check to see if the event comes from an object with an appropriate selector, and if so, execute your event handling code. This way, as objects come and go, their events are still handled appropriately.

As you were originally doing things, you would bind the event handler directly to the object that matched the selector 'section#attendance input:last' at the time the event binding code ran. From then on, it was bound directly to that specific object regardless of whether that object still matches the selector or if new objects are added to the DOM that would match the selector. Delegated event handling using .delegate() or .on() allows the event handling behavior to be more dynamic - automatically adjusting to changes in the DOM. You just have to bind the event to a common parent object that will not be changing and it can automatically monitor all it's children.

like image 92
jfriend00 Avatar answered Oct 30 '22 07:10

jfriend00