views:

61

answers:

3

Hi Guys

I keep getting the error links[i] is undefined. I define it explicitly and yet it keeps giving me that error -- any ideas?

I am trying to do unobtrusive image rolovers on 5 links that I have.

function loadImages(){
    path = 'uploads/Splash-4/nav/'; 
    links = new Array();

    for (i=1;i<=5;i++){
        var id = "link-"+i;
        var defaultState = '<img src="' +path+i+'.jpg" border="0" />';
        links[i] = document.getElementById(id);

        // Place all image linksinto anchor
        links[i].innerHTML = defaultState;

        // What to do on mouseover
        links[i].onmouseover = function() { 
            links[i].innerHTML = '<img src="' +path+i+'a.jpg" border="0" />';
        }
        // What to do on mouse oUt
        links[i].onmouseout = function() {
            links[i].innerHTML = defaultState;
        }
    }
}

window.onload = loadImages;

########## HTML
 <a href="?page=Profile" id="link-1"></a>
 <a href="?page=for-sale" id="link-2"></a><br />
 <a href="?page=testimonials" id="link-3"></a><br />
 <a href="?page=free-home-appraisal" id="link-4" /></a><br />
 <a href="?page=contact-me" id="link-5"></a><br />
A: 

Your code snippet doesn't include a declaration of the variable links. If you haven't defined it elsewhere (i.e., if it's a local variable), you'll need to do it here:

Instead of

links = new Array();

You could do

var links = new Array();

One example can be found here.

If you have declared it elsewhere, it could be that this line

document.getElementById(id);

is returning null.

Andy
It is permitted in javascript to declare variables without the `var` keyword. It just means you're making it global. It is good practice to *not* use global variables, but it won't cause the `undefined` in this case.
patrick dw
You are correct. I actually didn't know that...not doing so caused me a problem in the past, and after refactoring (including explicitly declaring the variable) my code worked, so I assumed that was a problem. Thank you for bringing this to the attention of those like me that thought otherwise.
Andy
@Andy - Yes it is almost always best to use `var`. Definitely an important standard practice to adopt.
patrick dw
+1  A: 

The problem is that when your onmouseover() function gets called, your variable i = 6 because your last iteration yielded i = 6, causing the loop to end. Therefore, you must protect i somewhere. For example :

function loadImages(){
    path = 'uploads/Splash-4/nav/'; 
    var links = [];

    for (i=1;i<=5;i++){
        (function(j) {
            var id = "link-"+j;
            var defaultState = '<img src="' +path+j+'.jpg" border="0" />';
            links[j] = document.getElementById(id);

            // Place all image linksinto anchor
            links[j].innerHTML = defaultState;

            // What to do on mouseover
            links[j].onmouseover = function() { 
                links[j].innerHTML = '<img src="' +path+j+'a.jpg" border="0" />';
            }
            // What to do on mouse oUt
            links[j].onmouseout = function() {
                links[j].innerHTML = defaultState;
            }
        })(i);  // call the anonymous function with i, thus protecting it's value for
                // the mouseover/mouseout

    }
}
Yanick Rochon
While that's true (nice closure example by the way), it isn't causing the `undefined` issue OP is having. He's using the `for()` loop as though the Array has a 1-based index.
patrick dw
This nearly works, but there is still somthing worng its not doing mousout properly, it does seem to be getting mixed up with the iteration, maybe doing it this way is not the best... see here http://generic.webeasy.com.au/index.php?page=sub-page
Andre
@patrick dw, thanks. even if the OP is using 1 as base index, it won't make any difference here, but it would if he's doing for (i=0; i<links.length; i++) { links[i]... } afterwards...@Andre, the mouseover/mouseout does seem awkward, but since I'm not sure what is the desire end result, I thought to keep it simple and simply try to address the issue. IMO, I would use .hover()
Yanick Rochon
Yes, you're right. I looked at it much too quickly, and didn't pay attention to the fact that OP was building the Array in the loop, not just referencing it.
patrick dw
+4  A: 

First off, you should be saying:

var links = [];

It's generally discouraged to use the Array constructor itself, and by not specifying var, you're making the links variable reside in the global space, which is generally bad.

Now, as to your actual problem.

Your event handlers are carrying a reference to the path and i variables from the outer scope, but by the time they're actually encountered, the variable i has the value 6 -- not what you intended at all! In order to fix that, you can change:

    // What to do on mouseover
    links[i].onmouseover = function() { 
        links[i].innerHTML = '<img src="' +path+i+'a.jpg" border="0" />';
    }
    // What to do on mouse oUt
    links[i].onmouseout = function() {
        links[i].innerHTML = defaultState;
    }

to

    // What to do on mouseover
    links[i].onmouseover = (function(path, i) {
        return function () {
            links[i].innerHTML = '<img src="' +path+i+'a.jpg" border="0" />';
        };
    })(path, i);
    // What to do on mouseout
    links[i].onmouseout = (function(i) {
        return function () {
            links[i].innerHTML = defaultState;
        }
    })(i);

This creates a new closure to hold the variables you want to capture. This way the inner i can still be, oh, 3 while the outer i goes to 6.

Anthony Mills