开发者

Javascript variable scope issue with jquery click event

I am trying to 开发者_Python百科assign a series of objects stored in an array to jquery click event handlers.

The problem is , when the event fires, I only ever references the last object in the array.

I have put together a simple example to show the problem:

function dothis() {
    this.btns = new Array('#button1', '#button2');
}

// Add click handler to each button in array:
dothis.prototype.ClickEvents = function () {

    //get each item in array:
    for (var i in this.btns) {

        var btn = this.btns[i];
        console.debug('Adding click handler to button: ' + btn);

        $(btn).click(function () {
            alert('You clicked : ' + btn);
            return false;
        });
    }
}

var doit = new dothis();
doit.ClickEvents();

The HTML form contains a couple of buttons:

<input type="submit" name="button1" value="Button1" id="button1" />
<input type="submit" name="button2" value="Button2" id="button2" />

When button1 is clicked, it says "You clicked #Button2"

It seems that both button click handlers are pointing to the same object inside var btn.

Considering the variable is inside the for loop, I cannot understand why.

Any ideas?


You need a function factory to close the loop variable, such as this:

//get each item in array:
for (var i=0; i<this.btns.length; i++) {

    $(this.btns[i]).click(function(item) { 
        return function () {
            alert('You clicked : ' + item);
            return false;
        }
    }(this.btns[i]));

}

Another good option is to let jquery help you. Use jQuery.each(). The variable btn here is local to the handler function, and so isn't reused between iterations. This allows you to close it and have it keep its value.

$.each(this.btns, function() {
    var btn = this;
    $(this).click(function () {
        alert('You clicked : ' + btn);
        return false;
    }
});


within an event handler, 'this' usually refers to the element firing the event, in this case, it would be your button

so the solution to your problem is fairly easy, instead of referencing the btn variable, which lives in a higher scope and gets mutated long before the event handler fires, we simply reference the element that fired the event and grab its ID

$(btn).click(function () {
  alert('You clicked : #' + this.id);
  return false;
});

Note: if your array contains other selectors that just the ID, this will obviously not reflect that and simply continue to show the ID

Lucky, the click handler (and all other event handlers afaik) take an extra parameter for eventData, useful like so:

$(btn).click(btn, function (event) {
  alert('You clicked : #' + event.data);
  return false;
});

User an array if you're passing multiple things:

$(btn).click(['foo', 'bar'], function (event) {
  alert('this should be "foo": ' + event.data[0]);
  alert('this should be "bar": ' + event.data[1]);
  return false;
});


you have to use closures for this. i'm not sure if i remember the correct syntax but you could try this:

$(btn).click(function () {
    return function() {
        alert('You clicked : ' + btn);
        return false;
    }
});


maybe you need to change just the click binding:

$(btn).click(function () {
    alert('You clicked : ' + $(this).attr('id'));
    return false;
});


Your problem is here:

alert('You clicked : ' + btn);

btn retains the value from the last time it was called in the loop. Read the value from the button in the event.

    $(btn).data('selector', btn).click(function () {
        alert('You clicked : ' + $(this).data('selector'));
        return false;
    });

http://jsfiddle.net/Mc9Jr/1/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜