tombolatwo
tombolatwo

Reputation: 33

Incrementing [i] in the for-loop does not work

this seems to be a simple question and I hope you can help me. I'd like to add that my code works the way I'm describing it. I'm not content with the way I solved my problem concerning my problem in incrementing [i] outside the for-loop.

What I want is to get a sidebar menu shown when one hovers over an image.

My CSS looks like:


GM_addStyle
(
'.colormenu {       \
 display:none;      \
 margin-left: 10px;     \
 margin-top: -55px;     \
 }              \
 .colormenu a {         \
 display: block;                \
 width: 30px;                   \
 }                          \
 .colorlist {                   \
 list-style-type: none;         \
 }                          \
'
);

Now I'm defining two variables. One containing some colors, the other containing some fruits.

var color = ['red','yellow','green','blue'];
var fruit = ['strawberry','banana','apple','blueberry'];

I then define two arrays:

var hoverstring = new Array(color.length);
var idstring = new Array(color.length);

Now I want to see whether the value of an element of var color matches a title of the images on the webiste. For every element being smaller than the length of var color I create two links in a list being wrapped by a div and insert it after a href wrapping the img-element.

for (var i=0;i<color.length;i++) {
 $("<div id='colormenu"+i+"' class='colormenu'><ul class='colorlist'><li><a href='path"+color[i]+"'>Call</a></li><li><a href='path"+color[i]+"'>Chat</a></li></ul><div>").insertAfter("a[href$='"+fruit[i]+"']"); 


 hoverstring[i]="img[title$='"+fruit[i]+"']:first";
 idstring[i]="#colormenu"+i;

}

The last step I take and this is where I got problems with is to create a function for every element. This is just an example of what it looks like:

    $(hoverstring[0]).hover(function(){
        $(idstring[0]).toggle();
    });
$(hoverstring[1]).hover(function(){ $(idstring[1]).toggle(); });
$(hoverstring[2]).hover(function(){ $(idstring[2]).toggle(); });
$(hoverstring[3]).hover(function(){ $(idstring[3]).toggle(); });
$(hoverstring[4]).hover(function(){ $(idstring[4]).toggle(); });
$(hoverstring[5]).hover(function(){ $(idstring[5]).toggle(); });

This method works, but is not very handy I'd say. Instead of creating a high amount of functions I'd like to increment i and not do it manually.

Like:


for (var i=0;i<color.length;i++) {
 $("<div id='colormenu"+i+"' class='colormenu'><ul class='colorlist'><li><a href='path"+color[i]+"'>Call</a></li><li><a href='path"+color[i]+"'>Chat</a></li></ul><div>").insertAfter("a[href$='"+fruit[i]+"']");




 hoverstring[i]="img[title$='"+fruit[i]+"']:first";
 idstring[i]="#colormenu"+i;


$(hoverstring[i]).hover(function(){
        $(idstring[i]).toggle();
    });
}

I tried it several times, but for some reason i isn't incremented in the for-loop. Have you got an idea why?

I really hope you can help me. Thank you in advance.

Upvotes: 3

Views: 3453

Answers (3)

Nick Craver
Nick Craver

Reputation: 630379

You can do something quick like this:

$.each(color, function(i) {
  $("<div id='colormenu"+i+"' class='colormenu'><ul class='colorlist'><li><a href='path"+this+"'>Call</a></li><li><a href='path"+this+"'>Chat</a></li></ul><div>").insertAfter("a[href$='"+fruit[i]+"']");
  $("img[title$='"+fruit[i]+"']:first").hover(function(){
    $("#colormenu"+i).toggle();
  });
});

The difference here is that i is scoped to this callback, not referencing the same variable that's changing with the loop each time.

Upvotes: 4

deceze
deceze

Reputation: 522032

It is incrementing i just fine, but the i inside your hover function is a reference to the i in the loop. After the loop is complete, the i inside the hover function, inside all hover functions, is the value of i after the loop. This is called a closure.

If you want to freeze the value of i at the specific point in time you create the function, you need to do this:

$(hoverstring[i]).hover((function (x) {
    return function () {
        $(idstring[x]).toggle();
    }
})(i));

Upvotes: 2

jAndy
jAndy

Reputation: 235992

You're facing one of biggest mistakes a ECMA-/ Javascript programmer can make:

Forgetting about closures and hoisting of variables.

Putting this in your for-loop:

$(hoverstring[i]).hover(function(){
    $(idstring[i]).toggle();
});

would cause that i would be closured by all of your methods. You need to invoke another function to solve that issue:

for (var i=0;i<color.length;i++) {
   $("<div id='colormenu"+i+"' class='colormenu'><ul class='colorlist'><li><a        href='path"+color[i]+"'>Call</a></li><li><a        href='path"+color[i]+"'>Chat</a></li></ul><div>").insertAfter("a[href$='"+fruit[i]+"']"); 


   hoverstring[i]="img[title$='"+fruit[i]+"']:first";
   idstring[i]="#colormenu"+i;

   (function(index){
       $(hoverstring[index]).hover(function(){
          $(idstring[index]).toggle();
       });
   }(i));
}

Upvotes: 2

Related Questions