Rob Stevenson-Leggett
Rob Stevenson-Leggett

Reputation: 35679

jQuery Closures, Loops and Events

I have a question similar to the one here: Event handlers inside a Javascript loop - need a closure? but I'm using jQuery and the solution given seems to fire the event when it's bound rather than on click.

Here's my code:

for(var i in DisplayGlobals.Indicators)
{
    var div = d.createElement("div");
    div.style.width = "100%";
    td.appendChild(div);

    for(var j = 0;j<3;j++)
    {
        var test = j;
        if(DisplayGlobals.Indicators[i][j].length > 0)
        {   
             var img = d.createElement("img");
             jQuery(img).attr({
                     src : DisplayGlobals.Indicators[i][j],
                     alt : i,
                     className: "IndicatorImage"
              }).click(
                     function(indGroup,indValue){ 
                         jQuery(".IndicatorImage").removeClass("active");
                         _this.Indicator.TrueImage = DisplayGlobals.Indicators[indGroup][indValue];
                         _this.Indicator.FalseImage = DisplayGlobals.IndicatorsSpecial["BlankSmall"];
                         jQuery(this).addClass("active"); 
                     }(i,j)
               );
               div.appendChild(img);   
          }
     }
}

I've tried a couple of different ways without success...

The original problem was that _this.Indicator.TrueImage was always the last value because I was using the loop counters rather than parameters to choose the right image.

Upvotes: 9

Views: 7311

Answers (3)

Dave Oleksy
Dave Oleksy

Reputation: 117

Nikita's answer works fine as long as you are using jQuery 1.4.3 and later. For versions previous to this (back to 1.0) you will have to use bind as follows:

.bind('click', {indGroup: i, indValue : j}, function(event) {
    alert(event.data.indGroup);
    alert(event.data.indValue);
    ...
});

Hope this helps anyone else still using 1.4.2 (like me)

Upvotes: 6

Nikita Rybak
Nikita Rybak

Reputation: 68006

Solution by Greg is still valid, but you can do it without creating additional closure now, by utilizing eventData parameter of jQuery click method (or bind or any other event-binding method, for that matter).

.click({indGroup: i, indValue : j}, function(event) {
    alert(event.data.indGroup);
    alert(event.data.indValue);
    ...
});

Looks much simpler and probably more efficient (one less closure per iteration).

Documentation for bind method has description and some examples on event data.

Upvotes: 13

Greg
Greg

Reputation: 321698

You're missing a function. The .click function needs a function as a parameter so you need to do this:

.click(
    function(indGroup,indValue)
    {
        return function()
        {
            jQuery(".IndicatorImage").removeClass("active");
            _this.Indicator.TrueImage = DisplayGlobals.Indicators[indGroup][indValue];
            _this.Indicator.FalseImage = DisplayGlobals.IndicatorsSpecial["BlankSmall"];
            jQuery(this).addClass("active"); 
        }
    }(i,j);
);

Upvotes: 14

Related Questions