Using a loop variable inside a function, javascript scoping confusion
I have built a dropdown menu system, everything works when tested independently, the problem I have is in the code below. I use the jQuery ready function to build the menu bar from an external array (menubar[]). Here I am trying to get the mouseover event to call the dropdown() function, but using a different argument for each anchor tag.
So rolling over the first should call dropdown(0), the second dropdown(1) and so on.
$(document).ready(function () {
for (i in menubar) {
var declaration = '<a href="' + baseurl + '/' + menubar[i].url +
'" class="menutitle">' + menubar[i].name + '</a>';
var a = $(declaration).mouseover(function () {
dropdown(i);
}).mouseout(function () {
activeTimer = setTimeout("removedropdowns()", 100);
});
$("#menu").append(a);
}
});
The code is calling dropdown(6); on each rollover. How can I pass the loop variable (i) into the mouseover function as a literal/static value!
I got this working fine in FF by 开发者_C百科using
.attr('onMouseOver','javascript:dropdown('+i+');')
but that wasn't firing for some versions of IE, so I switched to the jQuery mouseover, which fires, but I have the issue above :(
Your actual problem is that each of your mouseover callbacks uses the same i
you increase i
all the way up to 6, the callbacks still point to the same i
and therefore all use 6
as the value.
You need to make a copy of the value of i
, you can do this by using an anonymous function.
$(document).ready(function () {
// you should use (for(var i = 0, l = menubar.length; i < l; i++) here in case menubar is an array
for (var i in menubar) {
var declaration = '<a href="' + baseurl + '/' + menubar[i].url +
'" class="menutitle">' + menubar[i].name + '</a>';
(function(e) { // e is a new local variable for each callback
var a = $(declaration).mouseover(function () {
dropdown(e);
}).mouseout(function () {
activeTimer = setTimeout(removedropdowns, 100); // don't use strings for setTimeout, since that calls eval
});
$("#menu").append(a);
})(i); // pass in the value of i
}
});
$(function() {
$(menubar).each(function(i){
$("#menu").append('<a href="' + baseurl + '/' + menubar[i].url + '" class="menutitle">' + menubar[i].name + '</a>');
});
$("#menu a").hover(
function(){
dropdown($(this).index());
},
function(){
activeTimer = setTimeout("removedropdowns()", 100);
}
);
});
First, don't use for..in
but rather ordinary loop.
Second, I would just append the links first then apply the events later:
$(document).ready(function() {
for (var i = 0; i < menubar.length; i++) {
$("#menu").append('<a href="' + baseurl + '/' + menubar[i].url + '" class="menutitle">' + menubar[i].name + '</a>');
}
$("#menu a").each(function(index) {
$(this).mouseover(function() { dropdown(index); }).mouseout(function() { activeTimer = setTimeout("removedropdowns()", 100); });
});
});
Have a look here and here.
To capture the current value of i, you need to pass it as a parameter to another function where it can be captured as a local variable:
Try using jQuery's each()
function:
jQuery(function() {
jQuery.each(menubar, function(index, element) {
var declaration = '<a href="' + baseurl + '/' + element.url + '" class="menutitle">' + element.name + '</a>';
var a = $(declaration).mouseover(function() { dropdown(index); }).mouseout(function() { activeTimer = setTimeout("removedropdowns()", 100); });
$("#menu").append(a);
});
});
In JavaScript, if you don't declare your variable, it is defined globally. To fix this, add "var" in front of your i looping variable like this. UPDATE: As Sime noticed (see comment), you also need to pass the variable into the function, otherwise you form a closure on the i.
$(document).ready(function() {
for(var i in menubar) {
var declaration = '<a href="' + baseurl + '/' + menubar[i].url + '" class="menutitle">' + menubar[i].name + '</a>';
var a = $(declaration).mouseover(function(i) { dropdown(i); }).mouseout(function() { activeTimer = setTimeout("removedropdowns()", 100); });
$("#menu").append(a);
}
});
精彩评论