tags:

views:

97

answers:

5

Is there a better way than the implementation I have now? I'm concerned that the way I've done it is a little hackish and am wondering if there's a more elegant solution.

I want to change the "selected" element on the page by applying a CSS class to it, and remove the one that is currently selected. The code I have for changing the element's class:

function changeClass(element) {
    document.getElementById("nav").getElementsByClassName("selected")[0].className = "";
    element.className = "selected";
}

And the corresponding elements:

<div id="nav">
    <ul>
        <li><a href="#" onclick="changeClass(this)" class="selected">Main</a></li>
        <li><a href="#" onclick="changeClass(this)">Downloads</a></li>
        <li><a href="#" onclick="changeClass(this)">News</a></li>
        <li><a href="#" onclick="changeClass(this)">Forums</a></li>
        <li><a href="#" onclick="changeClass(this)">Proposals</a></li>
    </ul>
</div>

Again, this seems a little hacky. Is there a better way of accomplishing what I'm trying to do?

+3  A: 

Using the getElementByClassName isn't too recommended, because currently there are browser that don't fully support this functionnality (mainly IE). This is probably something that would work better on all browser :

<html>
<head>

<script type="text/javascript">
var previousElement = null;
function changeClass (newElement) {
     if (previousElement != null) {
          previousElement.className = "";
     }

     newElement.className = "selected";
     previousElement = newElement;
}

// just add a call to this function on the load of the page
function onload() {
     lis = document.getElementById("nav").getElementsByTagName("a");
     for (var i=0; i<lis.length; i++) {
          if (lis[i].className == "selected")
            previousElement = lis[i];
     }
}
</script>
<style type="text/css">
.selected {
    background: #0ee;
}
</style>
</head>
<body onload="onload()">
<div id="nav">
    <ul>
        <li><a href="#" onclick="changeClass(this)" class="selected">Main</a></li>
        <li><a href="#" onclick="changeClass(this)">Downloads</a></li>
        <li><a href="#" onclick="changeClass(this)">News</a></li>
        <li><a href="#" onclick="changeClass(this)">Forums</a></li>
        <li><a href="#" onclick="changeClass(this)">Proposals</a></li>
    </ul>
</div>
</body>
</html>
HoLyVieR
A: 

I recommend you to use a JavaScript library to do this. For example, with jQuery you could do something like this:

$("#nav .selected").removeClass("selected");

This would remove the "selected" class from all child elements of #nav that have the class "selected".

Bytecode Ninja
Is it really worth it to have a huge library for something as minor as this, since I have no other use for jQuery?
Corey
If what you are working on a is not a trivial Web site, I would recommend you to use a good JS library, be it jQuery, Prototype, or anything else.But if it is trivial and you don't mind to take care of cross-browser issues, then that's another problem...
Bytecode Ninja
+3  A: 

Here's how to do this with JQuery:

$(document).ready( function()
{
    $("a").click( function()
    {
        $(".selected").removeClass("selected");
        $(this).addClass("selected");
    } );
});

This clears the existing "selected" class and adds it to the one just clicked.

jdigital
A: 

There's not a lot wrong with what you've got.

Instead of getElementsByClassName, which isn't supported by IE, consider using getElementsByTagName to get all the <a> tags as an array, then iterating through that array, setting className to "" for each.

A Javascript library like jQuery or Prototype does indeed give you lots of functions specifically designed for this sort of work. But, unless you're doing a fair bit more Javascript than this, they're complete overkill.

Lastly, if your <a>s are intended to be back-up navigation in case Javascript is disabled, you probably want your onclick handlers to return false; that prevents the link from being followed. (In your case, to "#".)

Ed Daniel
A: 
<!doctype html>
<html lang="en">
<head>
<meta charset= "utf-8">
<title>Untitled Document</title>

<style type="text/css">
li{margin:1ex 1em}
ul.selectable a{color:blue;text-decoration:underline;font-size:2em}
ul.selectable a.selected{color:red;border:red dotted 1px}
</style>
<script type="text/javascript">
// It is easier to fake a lightweight forEach than 
//an  getElementsByClassName function


Array.prototype.forAll= function(fun){
    var L= this.length, tem;
    if(typeof fun== 'function'){
        while(L){
            fun(this[--L]);
        }
    }
}

// You could have just one handler, listening to the div or ul
// and running the function on the target it it is a hyperlink.

onload= function(){
    var pa= document.getElementById("nav"),
    collection= pa.getElementsByTagName('a');

    pa.onclick= function(e){
        e= window.event? event.srcElement: e.target;
        if(e.tagName== 'A'){
            [].forAll.call(collection,function(itm){
                itm.className= '';
            });
            e.className= "selected";
            return e.focus();
        }
        return true;
    }
}

</script>
</head>
<body>

<div id= "nav"> 
<ul class= "selectable"> 
<li> <a href= "#" class= "selected"> Main</a> </li> 
<li> <a href= "#"> Downloads</a> </li> 
<li> <a href= "#"> News</a> </li> 
<li> <a href= "#"> Forums</a> </li> 
<li> <a href= "#"> Proposals</a> </li> 
</ul> 
</div>

</body>
</html>
kennebec