Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 227
Rob Stevenson-Leggett Avatar asked Dec 11 '08 14:12

Rob Stevenson-Leggett


Video Answer


2 Answers

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);
);
like image 161
Greg Avatar answered Sep 24 '22 14:09

Greg


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.

like image 39
Nikita Rybak Avatar answered Sep 26 '22 14:09

Nikita Rybak