Reputation: 33
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
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
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
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