开发者

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);
    }
});
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜