Gal
Gal

Reputation: 5426

Dynamically add jQuery event

I'm trying to dynamically add buttons, and add a jQuery listening even to them. However, I'm having troubles with JavaScript's scoping (at least I think that's it is).

This is pretty much my code:

for (var item in group) {
    $('div').append("<input type='button' value='" + item + "' id = 'id" + item + "'>");
    $('#id' + item).click(function() {
        alert("Hello from " + item);
    });
}

Now the problem is that no matter which button I click, the alert inside the event callback always uses the last item.

Now I understand why this is happening (well, roughly :P), but how I can fix it?

Upvotes: 0

Views: 1511

Answers (8)

Adam Magaluk
Adam Magaluk

Reputation: 1726

Harmen,

Why not you jquery's live function.

It allows you to bind a function to an event on a set of objects with the jquery selector just like $('#button').click() does but also allows new elements that are appended in the future to also work with the click event. This would fit your dynamically requirement.

See the example below. I use the live function to bind click event to all elements that are a class 'testButton'. Then to get the value use the attr('value') on the $(this) because this is the element clicked.

var group = ["Test 1", "Test 2", "Test 3"];

     for (var item in group) {
         $('div').append("<input class='testButton' type='button' value='" +item+ "'>");  
     }

     $('.testButton').live('click', function(e) {
           alert('Hello Im From ' + $(this).attr('value'));
      });

Jquery Live Function : http://api.jquery.com/live/

Working Example : http://jsfiddle.net/bbP64/12/

Hope that helps.

Upvotes: 0

jfriend00
jfriend00

Reputation: 708106

I think everything is OK in your code except for using the item variable in the alert() statement.

Since the alert runs long after the for loop has finished, the alert will see the last value for item, not the one you want. If you just want to access the currently clicked on items ID, then you can just get that from the this reference rather than passing it in. Try changing your code to this:

for (var item in group) {
    $('div').append("<input type='button' value='" + item + "' id = 'id" + item + "'>");
    $('#id' + item).click(function() {
        alert("Hello from " + this.id.slice(2));
    });
}

Works here in this jsFiddle: http://jsfiddle.net/jfriend00/uyK3m/

Upvotes: 0

Digital Plane
Digital Plane

Reputation: 38284

The easy ways: pass some event data:

for (var item in group) {
    $('div').append("<input type='button' value='" + item + "' id = 'id" + item + "'>");
    $('#id' + item).click({item: item}, function(event) {
        alert("Hello from " + event.item);
    });
}

Or use event.target or this:

for (var item in group) {
    $('div').append("<input type='button' value='" + item + "' id = 'id" + item + "'>");
    $('#id' + item).click(function(event) {
        alert("Hello from " + event.target.id); //or this.id
    });
}

Upvotes: 0

Sinetheta
Sinetheta

Reputation: 9449

Most of answers above are correct, but unnecessarily verbose. "this" is your friend.

for (item in group) {
    $('div').append("<input type='button' value='" + item + "' id = 'id" + item + "'>");
    $('#id' + item).click(function() {
        alert("Hello from " + this.id.slice(2) );
    });
}

Upvotes: 0

maxedison
maxedison

Reputation: 17573

You can use jQuery's $.each method to iterate over the group array in the same way, but this will solve the issue for you:

    $.each(group,function(i,v){
        $('div').append("<input type='button' value='" + v + "' id = 'id" + v + "'>");
        console.log($('#id' + v))
        $('#id' + v).click(function() {
            alert("Hello from " + v);
        });
    });

http://jsfiddle.net/ebiewener/byV9X/

Upvotes: 1

Joe
Joe

Reputation: 82654

It works for me: http://jsfiddle.net/bgt89/ but i did change your handler to use closures.

var group = ['asdf', 'rere', 'eeeee']

$(document).ready(function() {
    for (var item in group) {
        $('div').append("<input type='button' value='" + item + "' id = 'id" + item + "'>");
        $('#id' + item).click((function(item) {
            return function() {
                alert("Hello from " + item);
            }
        })(item));
    }
});

Upvotes: 0

Tristan
Tristan

Reputation: 3885

one way of achieving this correctly is like so

for (var item in group) {
    $('div').append("<input type='button' value='" + item + "' id = 'id" + item + "'>");
    (function(item){
       $('#id' + item).click(function() {
          alert("Hello from " + item);
       });
    })(item);
}

here is a jsfiddle to demonstrate http://jsfiddle.net/reefbarman/bbP64/

Upvotes: 4

Steve Wellens
Steve Wellens

Reputation: 20638

I would look in to using the jQuery Delegate function.

http://api.jquery.com/delegate/

That will attach an event handler to a container. All the element events in the container will trickle up to the container and if handled will trigger the event handler.

Upvotes: 0

Related Questions