0

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?

8 Answers 8

4

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/

Sign up to request clarification or add additional context in comments.

Comments

1

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/

Comments

0

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.

Comments

0

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

Comments

0

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

Comments

0

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

Comments

0

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/

1 Comment

@Gal - There must be something else wrong in your actual code because it works fine here in the jsFiddle: jsfiddle.net/jfriend00/uyK3m.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.