/    Sign up×
Community /Pin to ProfileBookmark

Arrays of document.getElementById?

Hey,
I’m working on a rollover menu that is giving me some problems. Originally the images were accessed by going document.images[i].src and changing it. This worked fine and would access the image’s source. It didn’t work so great when I kept changing how many images came before the menu, thus messing up its order in the images array. It stopped being feasible completely when I used some PHP to make the number of images before the menu variable. So I reworked it by building a new array that referred to the 5 images id’s.

[CODE]
var menuImages = new Array();
menuImages[0] = document.getElementById(“homeButtonPic”);
menuImages[1] = document.getElementById(“productsButtonPic”);
menuImages[2] = document.getElementById(“toolsButtonPic”);
menuImages[3] = document.getElementById(“aboutusButtonPic”);
menuImages[4] = document.getElementById(“contactusButtonPic”);
[/CODE]

No warnings there. But when I try to access the source of those elements with this code below, it says menuImages[i] is null. ImgOver[i].src is the array of images containing the image which should be displayed when moused over.

[CODE]
if (document.images) menuImages[i].src = ImgOver[i].src;
[/CODE]

Are arrays of elements not allowed or is there some other issue?

to post a comment
JavaScript

13 Comments(s)

Copy linkTweet thisAlerts:
@Sterling_IsfineJan 23.2010 — What happens if you do this?
[CODE]
var menuImages = new Array();
menuImages[0] = document.getElementById("homeButtonPic");
alert( menuImages[0] );
[/CODE]
If it's null, then the element doesn't exist at that point.
Copy linkTweet thisAlerts:
@rpg2009Jan 23.2010 — Really you should be considering css sprite menus instead. Much easier, and will work if javascript is switched off.

Just one of the first links found on google.

http://css-tricks.com/css-sprites/

RE: your approach, which as far as I gather is a bit outdated.

Would be helpful to see your html, but also are you allowing the page to load first before trying to access the elements.

Maybe something like this.

[code=php]<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Default</title>
<style type="text/css">
</style>
<script type="text/javascript">
function init(){
//An array of our button names minus state
var navArr = ["home","product","tools","about","contact"];
// find the unordered list element by it's id "nav"
var nav = document.getElementById("nav");
// from that then find all child img elements of nav and return an array
var navImgs = nav.getElementsByTagName("img");

// navImgs is an array of all the img elements so we can now loop through them.
for ( var i = 0, len = navImgs.length; i < len; i+=1){
// add an index no so we can then pick the appropriate name from navArr in our handler functions
navImgs[i].indexNo = i;
// e.g. function(){this.src = "ASSETS/"+"home"+"On.jpg"}. This refers to the img element.
navImgs[i].onmouseover = function (){this.src = "ASSETS/"+navArr[this.indexNo]+"On.jpg";};
navImgs[i].onmouseout = function (){this.src = "ASSETS/"+navArr[this.indexNo]+"Off.jpg";};
}
}
window.onload = init; // we need to wait for the page to load before accessing dom elements.
</script>
</head>

<body>
<ul id = "nav">
<li><a href = "#"><img src = "ASSETS/homeOff.jpg" /></a></li>
<li><a href = "#"><img src = "ASSETS/productOff.jpg" /></a></li>
<li><a href = "#"><img src = "ASSETS/toolsOff.jpg" /></a></li>
<li><a href = "#"><img src = "ASSETS/aboutOff.jpg" /></a></li>
<li><a href = "#"><img src = "ASSETS/contactOff.jpg" /></a></li>
</ul>

</body>

</html>
[/code]


ps. You will also need an image preloader.

Hope this helps.

Cheers

RPG
Copy linkTweet thisAlerts:
@gatohoserauthorJan 23.2010 — When I alerted it at first, I got null so I realized it was like one of you said and it was an issue of the script running before the page fully loaded. So I reworked it a bit and below is what I have. The rollovers work, but if you try them when the page is loading you get the same errors. Also it seems as if the preloading doesn't work now. It seems to download each image when moused over.

[code=php]<?php
echo '
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>' . $title . '</title>
<link href="css/style.css" rel="stylesheet" type="text/css">
<script src="scripts/menus.js" type="text/javascript"></script>
<script src="scripts/averageusage.js" type="text/javascript"></script>
<script src="scripts/averagesun.js" type="text/javascript"></script>
<script src="scripts/accountcreation.js" type="text/javascript"></script>
<script src="scripts/index.js" type="text/javascript"></script>
<script type="text/javascript">
var menuImages = new Array(5);

if (document.images) {
var ImgOver = new Array();
ImgOver[0] = new Image;
ImgOver[1] = new Image;
ImgOver[2] = new Image;
ImgOver[3] = new Image;
ImgOver[4] = new Image;
ImgOver[0].src = "images/newHomeOver.png";
ImgOver[1].src = "images/newProductsOver.png";
ImgOver[2].src = "images/newSizingOver.png";
ImgOver[3].src = "images/newAboutOver.png";
ImgOver[4].src = "images/newContactOver.png";

var ImgOut = new Array();
ImgOut[0] = new Image;
ImgOut[1] = new Image;
ImgOut[2] = new Image;
ImgOut[3] = new Image;
ImgOut[4] = new Image;
ImgOut[0].src = "images/newHomeOut.png";
ImgOut[1].src = "images/newProductsOut.png";
ImgOut[2].src = "images/newSizingOut.png";
ImgOut[3].src = "images/newAboutOut.png";
ImgOut[4].src = "images/newContactOut.png";
}

function menuInit() {
menuImages[0] = document.getElementById("homeButtonPic");
menuImages[1] = document.getElementById("productsButtonPic");
menuImages[2] = document.getElementById("toolsButtonPic");
menuImages[3] = document.getElementById("aboutusButtonPic");
menuImages[4] = document.getElementById("contactusButtonPic");
}

function RollOver(i) {
if (document.images) menuImages[i].src = ImgOver[i].src;
}

function RollOut(i) {
if (document.images) menuImages[i].src = ImgOut[i].src;
}
</script>

</head>

<body id="top" onload ="menuInit()">
<div id="container">
<div id="header">
<img src="images/lighthouselogo.jpg" alt="Logo" align="left" height="125px">
<br><br>
';

if(!isLoggedIn())
{
echo '
<div id="headerCommands">
<a href="login.php">Log in</a>
<img src="images/bluespacer.gif" width="1" height="25" border="0">
<a href="cart.php">View Cart</a>
<img src="images/bluespacer.gif" width="1" height="25" border="0">
<a href="checkout.php">Checkout</a>
</div>
';
}else{
echo '
<div id="headerCommands">
<a href="login.php">' . $user['username'] . '</a>
<img src="images/bluespacer.gif" width="1" height="25" border="0">
' . $logout . '
<img src="images/bluespacer.gif" width="1" height="25" border="0">
<a href="cart.php">View Cart</a>
<img src="images/bluespacer.gif" width="1" height="25" border="0">
<a href="checkout.php">Checkout</a>
</div>
';
}
echo '
</div>

<div id="menu">
<ul>
<li id="home" class="menuHeader">
<a href="index.php"><img src="images/newHomeOut.png" id="homeButtonPic" name="homeButtonPic" alt="Home"
onmouseover="RollOver(0)" onmouseout="RollOut(0)"></a>
</li>
<li id="products" class="menuHeader">
<a href="products.php"><img src="images/newProductsOut.png" id="productsButtonPic" name="productsButtonPic" alt="Products"
onmouseover="RollOver(1)" onmouseout="RollOut(1)"></a>
</li >
<li id="sizing" class="menuHeader">
<a href="averageusage.php"><img src="images/newSizingOut.png" id="toolsButtonPic" name="toolsButtonPic" alt="Tools"
onmouseover="RollOver(2)" onmouseout="RollOut(2)"></a>
</li >
<li id="aboutUs" class="menuHeader">
<a href="aboutus.php"><img src="images/newAboutOut.png" id="aboutusButtonPic" name="aboutusButtonPic" alt="About Us"
onmouseover="RollOver(3)" onmouseout="RollOut(3)"></a>
</li>
<li id="contactUs" class="menuHeader">
<a href="contactus.php"><img src="images/newContactOut.png" id="contactusButtonPic" name="contactusButtonPic" alt="Contact Us"
onmouseover="RollOver(4)" onmouseout="RollOut(4)"></a>
</li>
</ul>
</div>
';
?>
[/code]


rpg2009: I appreciate the code you gave me and I might switch to use it in the end. For now I want to try and fix this code as I am really developing this site for practice and so I want to see what I don't understand with my code. I'm sure I'll learn something in fixing this bug.
Copy linkTweet thisAlerts:
@gatohoserauthorJan 23.2010 — Oh by the way this is just the header PHP file. Should have mentioned that.
Copy linkTweet thisAlerts:
@rpg2009Jan 23.2010 — For now I want to try and fix this code as I am really developing this site for practice and so I want to see what I don't understand with my code.[/QUOTE]

Understand where you're coming from, if it's a learning exercise go for it.?

I'm not an expert gatohoser as my sig points out, but I still think in the end you would be better off dropping javascript and going the CSS route instead.

A simple rollover I've just knocked up (Note my CSS isn't great).

http://www.pixel-shack.com/critter/SimpleRollover.html

Three advantages I can think of. You only need to download one image for all states, your html is less cluttered so more accessible and it works with javascript switched off.

[code=php]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Default</title>
<style type="text/css">
body {background-color: #333; color: #ccc;}

ul#nav {
float: left;
margin: 0px; padding: 0px;
list-style: none;
border: 1px solid #444;
}

ul#nav li{
float: left;
}

ul#nav li a{
display: block;
width: 107px; height: 33px; /* Size of button */
color: #ccc;
font: 12px/23px verdana;
text-align: center;
text-decoration: none;
background: url("ASSETS/Buttons.jpg") top left; /* inactive vertically at the top */
}

ul#nav li a:hover { /* onhover move the background image vertically to the centre */
color: white; background-position: center left;
}

ul#nav li a:active { /* onclick move the background image vertically to the bottom */
color: white; background-position: bottom left;
}

.clear {clear: both;}
</style>

</head>
<body>
<ul id="nav">
<li><a href="#">home</a></li>
<li><a href="#">products</a></li>
<li><a href="#">tools</a></li>
<li><a href="#">about</a></li>
<li><a href="#">contact</a></li>
</ul>

<div class="clear">&nbsp;</div>
<p><img src = "ASSETS/Buttons/Buttons.jpg" /> The full sprite image used 107x99px.</p>
</body>
</html>
[/code]


RPG
Copy linkTweet thisAlerts:
@gatohoserauthorJan 24.2010 — Thanks again RPG! I'll definitely go that route (CSS sprites) in the end before I publish for the 3 reasons you mentioned.

Does anyone see whats wrong with my code that is causing the problems I described?
Copy linkTweet thisAlerts:
@gatohoserauthorJan 29.2010 — Just a bump to see if anyone can figure out why my JavaScript rollovers don't work exactly as intended.
Copy linkTweet thisAlerts:
@WebnerdJan 30.2010 — Problem is that you need to "bind" your events to the images upon page load. Using inline Javascript events is also a bit deprecated. Basically, in your onload event, you need to assign your "mouseover" and "mouseout" functions to those elements.

Problem is, you can still access those events even when init() hasn't fired.

You could also set a global variable called:

<i>
</i>var initialized = false;


and set that to true at the end of the init

<i>
</i> function menuInit() {
menuImages[0] = document.getElementById("homeButtonPic");
menuImages[1] = document.getElementById("productsButtonPic");
menuImages[2] = document.getElementById("toolsButtonPic");
menuImages[3] = document.getElementById("aboutusButtonPic");
menuImages[4] = document.getElementById("contactusButtonPic");
initialized = true;
}



and then add that to your rollovers

<i>
</i>function RollOver(i)
{
if(!initialized) return
if (document.images) menuImages[i].src = ImgOver[i].src;
}
Copy linkTweet thisAlerts:
@gatohoserauthorJan 30.2010 — Problem is that you need to "bind" your events to the images upon page load. Using inline Javascript events is also a bit deprecated. Basically, in your onload event, you need to assign your "mouseover" and "mouseout" functions to those elements.
[/QUOTE]


The fix is great! I see how that will solve the issue. But could you clarify on the quoted text? I'm not sure what you mean by bind events to the images. Also what is meant by "inline" events. Could you show an example of what I would need to do? Thanks for your help!
Copy linkTweet thisAlerts:
@WebnerdFeb 02.2010 — There are methods of attaching event listeners through Javascript without having to "crap-up" your HTML code.

https://developer.mozilla.org/En/DOM/Element.addEventListener

and

https://developer.mozilla.org/En/DOM/Element.addEventListener

Javascript frameworks build this functionality in for ease of use.
Copy linkTweet thisAlerts:
@gatohoserauthorFeb 02.2010 — I'm having a heck of a time figuring this out. Here's what I have:

[CODE] <script type="text/javascript">
var menuImages = new Array(6);

if (document.images) {
var ImgOver = new Array();
ImgOver[0] = new Image;
ImgOver[1] = new Image;
ImgOver[2] = new Image;
ImgOver[3] = new Image;
ImgOver[4] = new Image;
ImgOver[5] = new Image;
ImgOver[0].src = "images/newHomeOver.png";
ImgOver[1].src = "images/newProductsOver.png";
ImgOver[2].src = "images/newSizingOver.png";
ImgOver[3].src = "images/newContractorsOver.png";
ImgOver[4].src = "images/newAboutOver.png";
ImgOver[5].src = "images/newContactOver.png";

var ImgOut = new Array();
ImgOut[0] = new Image;
ImgOut[1] = new Image;
ImgOut[2] = new Image;
ImgOut[3] = new Image;
ImgOut[4] = new Image;
ImgOut[5] = new Image;
ImgOut[0].src = "images/newHomeOut.png";
ImgOut[1].src = "images/newProductsOut.png";
ImgOut[2].src = "images/newSizingOut.png";
ImgOut[3].src = "images/newContractorsOut.png";
ImgOut[4].src = "images/newAboutOut.png";
ImgOut[5].src = "images/newContactOut.png";
}

function RollOver(i) {
if (document.images) menuImages[i].src = ImgOver[i].src;
}

function RollOut(i) {
if (document.images) menuImages[i].src = ImgOut[i].src;
}

function menuInit() {
menuImages[0] = document.getElementById("homeButtonPic");
menuImages[1] = document.getElementById("productsButtonPic");
menuImages[2] = document.getElementById("toolsButtonPic");
menuImages[3] = document.getElementById("contractorsButtonPic");
menuImages[4] = document.getElementById("aboutusButtonPic");
menuImages[5] = document.getElementById("contactusButtonPic");

for (i = 0; i < menuImages.length; i++) {
alert("made it here and " + i + " is i");
menuImages[i].addEventListener("onmouseover", RollOver(i), false);
alert("made it here too");
menuImages[i].addEventListener("onmouseout", RollOut(i), false);
}
}
</script>

</head>

<body id="top" onload ="menuInit()">[/CODE]


This fires an exception because of the name of the function. RollOver can not have a parameter as far as I can figure. RollOver(i) does not work but RollOver would as a parameter of addEventListener. But if I lose the i, then I don't know what image to choose. I can find the element that fired the event using window.event.srcElement but this doesn't carry the "i" anymore to say which element of ImgOver[] to use. Any clues?

Thanks for pointing me in the more modern JavaScript direction!
Copy linkTweet thisAlerts:
@rpg2009Feb 03.2010 — A few possibilities.

[code=php]function iD(id){return document.getElementById(id);} // saves typing document.getElementById each time

menuImages = [];
menuImages[0] = iD("homePic");
menuImages[1] = iD("productsPic");
menuImages[2] = iD("toolsPic");
menuImages[3] = iD("aboutPic");
menuImages[4] = iD("contactPic");

for (i = 0, len = menuImages.length; i < len; i+=1) {
menuImages[i].onmouseover = function(){rollOver(this);}; // this refers to the current image element
menuImages[i].onmouseout = function(){rollOut(this);}; // this refers to the current image element
}

function rollOver(x){
// e.g. x = <img id="homePic" src="images/newHomeOut.png"> The image element which fired the event
x.src = x.src.replace(/Out/,"Over"); //e.g. images/newHomeOut.png is replaced with images/newHomeOver.png
}

function rollOut(x){
x.src = x.src.replace(/Over/,"Out");
}[/code]


If you want to pass the i. I have already posted this option in post#3

[code=php]for (i = 0, len = menuImages.length; i < len; i+=1) {
menuImages[i].indexNo = i; // value i is assigned to a new property indexNo
menuImages[i].onmouseover = function(){ rollOver(this.indexNo) };
menuImages[i].onmouseout = function(){ rollOut(this.indexNo) };
}

function rollOver(x){
console.log(x);
}

function rollOut(x){
console.log(x);
}[/code]


or

[code=php]for (i = 0, len = menuImages.length; i < len; i+=1) {
menuImages[i].onmouseover = (function(x){ return function(){rollOver(x);}})(i);
menuImages[i].onmouseout = (function(x){ return function(){rollOut(x);}})(i);
}

function rollOver(x){
console.log(x);
}

function rollOut(x){
console.log(x);
}[/code]


RPG
Copy linkTweet thisAlerts:
@rpg2009Feb 03.2010 — I did this one as a bit of a refresher for myself. You only have to add event handlers to a containing element, rather than each individual image element. It relies on bubbling instead.

[code=php]<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Default</title>
<style type="text/css">
body {background-color: #333; color: #ccc;}
a img { border: none; }
ul#nav { float: left; margin: 0px; padding: 0px; list-style: none; border: 1px solid #444;}
ul#nav li{ float: left; }
ul#nav li a{ display: block; width: 107px; height: 33px; outline: none; }
</style>
</head>
<body>
<ul id = "nav">
<!-- replace src names with your filenames -->
<li><a href="#"><img id = "homePic" src="ASSETS/Buttons/ButtonOut.jpg" /></a></li>
<li><a href="#"><img id = "productsPic" src="ASSETS/Buttons/ButtonOut.jpg" /></a></li>
<li><a href="#"><img id = "toolsPic" src="ASSETS/Buttons/ButtonOut.jpg" /></a></li>
<li><a href="#"><img id = "aboutPic" src="ASSETS/Buttons/ButtonOut.jpg" /></a></li>
<li><a href="#"><img id = "contactPic" src="ASSETS/Buttons/ButtonOut.jpg" /></a></li>
</ul>
<script type="text/javascript">
function iD(id){return document.getElementById(id);} // saves typing document.getElementById each time

function handler (element, type, fn){
if (element.addEventListener) {element.addEventListener(type, fn, false);} // if mozilla
else if (element.attachEvent) {element.attachEvent('on'+type, fn);} // if IE
else {element['on'+type] = fn;} // a fallback for older browsers.
}

// Add the events to the main nav container element
var navElement = iD("nav");
handler (navElement, "mouseover", rollOver);
handler (navElement, "mouseout", rollOver);

function rollOver(e){ // Out handler function
var event = e ? e: window.e; // mozilla : IE
var target = event.target || event.srcElement; // mozilla : IE. What element fired the event?
var eventType = event.type; // mouseover? mouseout?
if (target.nodeName === "IMG") { // is the element an img type
var currSrc = target.src;
target.src = (eventType === "mouseover") ? currSrc.replace(/Out/,"Over") : currSrc.replace(/Over/,"Out");
}
}
</script>
</body>
</html>[/code]


RPG
×

Success!

Help @gatohoser spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 BETA 5.18,
whats_new: community page,
up_next: more Davinci•003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinci•003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @AriseFacilitySolutions09,
tipped: article
amount: 1000 SATS,

tipper: @Yussuf4331,
tipped: article
amount: 1000 SATS,

tipper: @darkwebsites540,
tipped: article
amount: 10 SATS,
)...