2

sorry this may be a simple question. I am trying to build my first navigation using jQuery. The idea is that on hover of the button that the background colour and text colour changes as long as it is not the 'selected' button. I have all this working fine apart from the text colour. As in the jQuery it cannot see my loop variable:

function testIndex(navIndex){
        for(i=0; i<=4; i++){
            if(i != navIndex){
                $('#nav a:eq('+i+')').hover(function(){
                    $(this).fadeTo('fast', 0.3, function(){
                        $(this).css('background-color','#ff3520');
                        $('#nav li:eq('+i+')').css('color', '#ffffff');
                    }).fadeTo('fast', 1);
                },
                function(){
                    $(this).fadeTo('fast', 0.3, function(){
                        $(this).css('background-color', '#e8e8e8');
                        $('#nav li:eq('+i+')').css('color', '#ff3520');
                    }).fadeTo('fast', 1);
                });
            };  
        };
    };

On the

$('#nav li:eq('+i+')').css('color', '#ff3520');

The 'i' variable cannot be seen. I've tested it by inserting my own variables and it works.

Any advice?

Thanks.

Brad
  • 159,648
  • 54
  • 349
  • 530
Dominic Sore
  • 397
  • 2
  • 4
  • 14
  • 1
    Can you elaborate on "Cannot be seen"? – jli Aug 16 '12 at 15:21
  • 2
    What if you change the `for` statement to `for(var i=0; i<=4; i++)`? – Richard Ev Aug 16 '12 at 15:21
  • 1
    Add `var` in front of `i` otherwise you'll only get the last value, as your variable is global – nico Aug 16 '12 at 15:22
  • The variable can not be seen. Sounds like a job for H.P. Lovecraft. – Alex Howansky Aug 16 '12 at 15:23
  • @jli As in cannot be used by the $('#nav li:eq('+i+')').css('color', '#ff3520'); section. However, it can be used by $('#nav a:eq('+i+')').hover(function()... – Dominic Sore Aug 16 '12 at 15:24
  • @RichardEv I have just given this a go and still nothing? – Dominic Sore Aug 16 '12 at 15:25
  • @nico and Richard Ev: That will not work in JavaScript. – gray state is coming Aug 16 '12 at 15:27
  • Please have a lok at http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example. But there is likely a better solution for your problem, please post an example of your HTML structure. – Felix Kling Aug 16 '12 at 15:32
  • @user1600680: why? It generally works for me in cases like yours... – nico Aug 16 '12 at 16:42
  • @nico: Not in JavaScript. There is no block scope, so there is only one `i` variable scoped to the function, which means it is overwritten in the loop. Since all the handlers made in the loop are referring to the same `i` variable, they will all get the value it was left at after the loop completed. – gray state is coming Aug 16 '12 at 16:54
  • @nico: Here is a demo with the for loop. http://jsfiddle.net/PQYNE/ and here is one with `i` scoped in a function. http://jsfiddle.net/PQYNE/1/ – gray state is coming Aug 16 '12 at 17:07
  • @user1600680: weird, I am pretty sure I had some situation like that, which I solved by just adding `var`. Evidently the situation was not *exactly* like that. – nico Aug 17 '12 at 08:31

2 Answers2

5

Because you are in a loop, need a variable scope to keep reference to i in the handler.

function testIndex(navIndex){
    $.each(Array(5), function(i) {
        if(i != navIndex){
            $('#nav a:eq('+i+')').hover(function(){
                $(this).fadeTo('fast', 0.3, function(){
                    $(this).css('background-color','#ff3520');
                    $('#nav li:eq('+i+')').css('color', '#ffffff');
                }).fadeTo('fast', 1);
            },
            function(){
                $(this).fadeTo('fast', 0.3, function(){
                    $(this).css('background-color', '#e8e8e8');
                    $('#nav li:eq('+i+')').css('color', '#ff3520');
                }).fadeTo('fast', 1);
            });
        }
    });
}

In JavaScript calling a function makes a variable scope, so I used $.each for the loop, because it calls the function for each array index.

gray state is coming
  • 2,107
  • 11
  • 20
1

It has already been explained what the problem with your code is (scope of i) and solutions have been provided. Also have a look at this related question: JavaScript closure inside loops – simple practical example.

However you can solve it differently, not using an index at all but using DOM traversal, in a more jQuery-oriented way. I assume your HTML looks similar to this:

<ul id="#nav">
    <li><a>...</a></li>
    <li><a>...</a></li>
</ul>

i.e. the a elements are descendants of the li you want to change.

You can then achieve the same with the following code:

function testIndex(navIndex){
    $('#nav a').slice(0,5).not(function(i) { 
        return i === navIndex;
    }).hover(function(){
        $(this).fadeTo('fast', 0.3, function(){
            $(this).css('background-color','#ff3520')
              .closest('li').css('color', '#ffffff');
         }).fadeTo('fast', 1);
    }, function(){
        $(this).fadeTo('fast', 0.3, function(){
            $(this).css('background-color', '#e8e8e8');
              .closest('li').css('color', '#ff3520');
        }).fadeTo('fast', 1);
    });
}
Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143