Prasun asks the CSS Guy how to switch the “on” state of navigation links for dynamic pages

Prasun writes:

I have a list of links in an unordered list. What I want is that when I click a list item, its color should change, and when I click some other list item, the color of the item which I clicked previously should return to its original state.

Can you help me in this regard?

Yes, I can help.

More advanced readers, move along. This is JavaScript beginner territory, but this is one of those steps that is really rich in DOM scripting nutrients, so I’m very pleased to discuss it.

What Prasun is describing, just by itself, is the behavior of a set of radio buttons. You click one, and it takes on the selected state. Then you click on another one, and the new one now becomes selected, while the previous one returns to an unselected state.

But radio buttons are form elements, not navigational elements, and upon clarifying with Prasun, it’s navigation that we’re after.

This is the fundamental behavior of a site that uses ajax for navigation or tabs, where each “page” is created by loading new content into the content section of the current page.

This is a relatively easy way to get your feet wet with DOM scripting. So I’ll first show how to do it with some very basic JavaScript functions. Also, I’ll show how to do it with jQuery.

First, the HTML

Let’s start with an unordered list of links.

<ul>
  <li><a href="#">Heartbreak Hotel</a></li>
  <li><a href="#">Blue Suede Shoes</a></li>
  <li><a href="#">Hound Dog</a></li>
  <li><a href="#">Don't Be Cruel</a></li>
  <li><a href="#">Teddy Bear</a></li>
</ul>

See example 1.

Who are we kidding? Let’s see it with some basic styling – example 2.

Since we’re going to be changing around selected links, let’s establish what a selected state looks like, and mark one item as selected by default. I’m going to do this by applying class="selected" to one of the links.

<ul>
  <li><a href="#">Heartbreak Hotel</a></li>
  <li><a href="#">Blue Suede Shoes</a></li>
  <li><a href="#" class="selected">Hound Dog</a></li>
  <li><a href="#">Don't Be Cruel</a></li>
  <li><a href="#">Teddy Bear</a></li>
</ul>

See example 3.

The JavaScript

Here’s what we want to do in English. When someone clicks a link, remove class=”selected” from any of the other links, and assign it to this one.

Another way to say that is “When someone clicks a link, run a function” and later I can be more specific about what that function is. Here’s how I’ll put that statement in the html.

<ul>
  <li><a onclick="applySelectedTo(this);" href="#">Heartbreak Hotel</a></li>
  <li><a onclick="applySelectedTo(this);" href="#">Blue Suede Shoes</a></li>
  <li><a onclick="applySelectedTo(this);" href="#" class="selected">Hound Dog</a></li>
  <li><a onclick="applySelectedTo(this);" href="#">Don't Be Cruel</a></li>
  <li><a onclick="applySelectedTo(this);" href="#">Teddy Bear</a></li>
</ul>

The “this” mentioned in the parentheses refers to the link that is being clicked. I’m thinking ahead here – I know that I’ll want to do something with the link being clicked (assign it class=”selected”), so I’m going to go ahead and pass that link as a parameter to the function. The term this is great for that sort of thing.

The function will be called “applySelectedTo()”, and I’ll write it in just a second. It’s going to do exactly what it says it will do: Apply class=”selected” to whatever link is given to it. It will also live in head of the document.

Notice that in the html, I’m passing the parameter this. And when I write the function, I’m using a made up term to help tell me what this was – the word link.

<script type="text/javascript">
function applySelectedTo(link) {
  link.className = "selected";
}
</script>

Check out Example 4 to see it in action.

Oh, but we’re not done

All that JavaScript function did was add class=”selected” to the new link. It didn’t remove class=”selected” from previously selected links. We need to fix that. Also, when we click a link, it adds the hash mark (#) to our url, and if our page were really long, it would jump to the top of the page again.

We’ll tackle the second problem first. That hash mark is telling me something: it’s indicating that the link is behaving like a link is supposed to behave. That behavior normally means that it will find the id of whatever I specified after the hash mark and the browser will bring that part of the page in focus. But in this case, we would rather ignore the default behavior of the link, so I’m going to tell my links to ignore their default behavior when clicked.

<ul>
  <li><a onclick="applySelectedTo(this);return false;" href="#">Heartbreak Hotel</a></li>
  <li><a onclick="applySelectedTo(this);return false;" href="#">Blue Suede Shoes</a></li>
  <li><a onclick="applySelectedTo(this);return false;" href="#" class="selected">Hound Dog</a></li>
  <li><a onclick="applySelectedTo(this);return false;" href="#">Don't Be Cruel</a></li>
  <li><a onclick="applySelectedTo(this);return false;" href="#">Teddy Bear</a></li>
</ul>

Example 5

And back to the first problem – removing class=”selected” from other links when a new link is selected. How do we get the link that already has class=”selected”, and remove the class? Well, to make it easy, I’m just going to say remove class=”selected” from all links, then I’ll add class=”selected” to the one just clicked.

<script type="text/javascript">
function applySelectedTo(link) {
  var ul = document.getElementsByTagName("ul")[0];
  var allLinks = ul.getElementsByTagName("a");
  for (var i=0; i<allLinks.length; i++) { 
    allLinks[i].className = ""; 
  } 
  link.className = "selected"; 
}
</script>

And so there you have it, Example 6 – final example.

And if you’re so inclined, make it do something.

We could go much further

Ideally, you wouldn’t even have an onclick attribute in the markup. That kind of thing can be inserted dynamically using more DOM scripting. It makes your html lots more readable and reusable, as well as separating behavior from structure.

Also, for kicks, here’s one final example of doing the things mentioned in this article, but using the jQuery library instead of self-written scripts. In the instance that you are already pulling in a hefty JavaScirpt library into your web site, you might as well make use of it.