Member Avatar for xander85

The Javascript first...

(Purpose: When a user hovers over any link that is contained inside of a <li> tag, then change the background color of the <li>...)

1 - May have an issue with my elements, being that it is not possible to change the background on <li> elements...

2 - Possibly an issue of where I am using the "SomeElement".parentNode...

3 - Some other issue that I may be overlooking...

window.onload = initMenu();

function initMenu() {
    for(i=0; i < document.links.length; i++) { 
        var thisLink = document.links[i];
        if(thisLink.parentNode.tagName == "LI"){
            setActivity(thisLink);
        }
    }
}

function setActivity(thisLink){
    thisLink.onmouseover = mouseOver(thisLink);    
    thisLink.onmouseout = mouseOut(thisLink);
}

function mouseOver(thisLink) {
    this.style.backgroundColor = '#D3FF06';
    return this;
}

function mouseOut(thisLink) {
    this.style.backgroundColor = '#171717';
    return this;
}

That is the way the Javascript file reads for the site that I am building. Though, it is not functioning. If a Javascript connoisseur will be so kind to point out any syntactical/logical errors please do. I have been trying to make this work and haven't been able to for a few days now; while working on other projects...

You're on the right track but need to change a few things. Here's the revised code with a comment number next to the changes:

window.onload = initMenu; // 1

function initMenu() {
	var links=document.getElementsByTagName('a'); // 2
    for(i=0; i < links.length; i++) { 
        var thisLink = links[i];
        if(thisLink.parentNode.tagName == "LI"){
            setActivity(thisLink);
        }
    }
}

function setActivity(thisLink){
    thisLink.onmouseover = mouseOver;    // 3
    thisLink.onmouseout = mouseOut;
}

function mouseOver() {
    this.parentNode.style.backgroundColor = '#D3FF06';  // 4
    return this;
}

function mouseOut() {
    this.parentNode.style.backgroundColor = '#171717';
    return this;
}

1. When you're setting in an event handler, you only need to assign the function to the handler. In your code, you were calling the actual function rather than assigning it. This meant initMenu() ran before the browser had even gotten to creating the DOM nodes.

2. Whenever possible, you should always use the W3C 'document.getElements...' methods rather than collections such as document.links, .forms or .images.

3. Again, you only need to assign the handler, not call it.

4. Whenever a handler is fired, the 'this' keyword points to the element that you registered it against. In this case you registered 'onmouseover' against a link, so use .parentNode to access the list item.

Hope that makes sense!

commented: Thanks for your help! That will help! +2

Whenever possible, you should always use the W3C
'document.getElements...' methods rather than collections such as
document.links, .forms or .images

links is a standard property of the document DOM element. It would be interesting to know the reasons of preferring the long winded and probably expensive document.getElementsByTagName() route.

@xander85:
AFAICR, there is a pure CSS solution which perfectly fits your scenario. I can't think of a better solution than letting the rendering engine do all the heavy lifting for you rather than you doing it yourself. The CSS solution has the advantage of working even when Javascript is disabled. Maybe something like:

li a {
  background-color: #999;
}
li a:hover {
  background-color: #333;
}
commented: I should have thought of that, THANKS! +2
Member Avatar for xander85

You're on the right track but need to change a few things. Here's the revised code with a comment number next to the changes:

window.onload = initMenu; // 1

function initMenu() {
	var links=document.getElementsByTagName('a'); // 2
    for(i=0; i < links.length; i++) { 
        var thisLink = links[i];
        if(thisLink.parentNode.tagName == "LI"){
            setActivity(thisLink);
        }
    }
}

function setActivity(thisLink){
    thisLink.onmouseover = mouseOver;    // 3
    thisLink.onmouseout = mouseOut;
}

function mouseOver() {
    this.parentNode.style.backgroundColor = '#D3FF06';  // 4
    return this;
}

function mouseOut() {
    this.parentNode.style.backgroundColor = '#171717';
    return this;
}

1. When you're setting in an event handler, you only need to assign the function to the handler. In your code, you were calling the actual function rather than assigning it. This meant initMenu() ran before the browser had even gotten to creating the DOM nodes.

2. Whenever possible, you should always use the W3C 'document.getElements...' methods rather than collections such as document.links, .forms or .images.

3. Again, you only need to assign the handler, not call it.

4. Whenever a handler is fired, the 'this' keyword points to the element that you registered it against. In this case you registered 'onmouseover' against a link, so use .parentNode to access the list item.

Hope that makes sense!

1. When you're setting in an event handler, you only need to assign the function to the handler. In your code, you were calling the actual function rather than assigning it. This meant initMenu() ran before the browser had even gotten to creating the DOM nodes.

Makes perfect sense, thanks for clarifying my error! great post. I have also made the other changes to my code. Works great!

4. Whenever a handler is fired, the 'this' keyword points to the element that you registered it against. In this case you registered 'onmouseover' against a link, so use .parentNode to access the list item.

I had this before, should have never touched that. Thanks for pointing that out. Would have cause more unneeded angst...

As for the pure CSS solution, that would work only with the background color of that particular element, this case the anchor. There is no way to select the parent of an element using pure CSS; that I know of...

A pure CSS solution:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Script-Content-Type" content="text/javascript">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Example</title>
    <style type="text/css">
      li a {
        background-color: #abc;
      }
      li a:hover {
        background-color: #def;
      }
    </style>
  </head>
  <body id="bdy">
    <div>
    <ul>
      <li><a href="http://www.google.co.in/">Google</a></li>
    </ul>
    </div>
  </body>
</html>
Member Avatar for xander85

A pure CSS solution:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Script-Content-Type" content="text/javascript">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Example</title>
    <style type="text/css">
      li a {
        background-color: #abc;
      }
      li a:hover {
        background-color: #def;
      }
    </style>
  </head>
  <body id="bdy">
    <div>
    <ul>
      <li><a href="http://www.google.co.in/">Google</a></li>
    </ul>
    </div>
  </body>
</html>

That only changes the anchors background color, not the <li></li> background color...

If that's your requirement then you need to change your original code which is as of now setting the onmouseover property of A elements and not LI elements in which the A elements are nested i.e. instead of thisLink, the element in consideration should be thisLink.parentNode.

@ ~s.o.s~ - there are a few reasons I'd use getElementsByTagName. The first is that the links collection only includes anchors with an href attribute; its unlikely but still possible that an <a> tag might not have this attribute when the page is loaded (some other script might add it, for example).

Secondly, you can use it on any element in your document, not just the root node. That wasn't required in this circumstance, but if xander85 happens to look up some documentation about it, he'll learn how useful it can be.

Lastly, its simply a more modern way of doing things (and is not very process-intensive at all). Google 'getElementsByTagName' and the chances are you'll come across some current stuff regarding recent browsers and DOMs; maybe you'll read about 'getElementsByClassName' too. Google 'document.links' and you'll find articles talking about Netscape 2 - no thanks.

> Secondly, you can use it on any element in your document, not
> just the root node.

Agreed; looking up anchor elements nested inside a given node would be one of the valid reasons for using getElementsByTagName().

> and is not very process-intensive at all

The reason I said it was a bit processing intensive is because the links collections of the document element is populated when the DOM is created out of the markup but getElementsByTagName requires a traversal through the entire DOM tree to collect all those anchor elements. So, even though it isn't processing intensive in an absolute sense, when compared to document.links, it surely looks so.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.