6

I have a simple menu in HTML:

<ul id="menu">
    <li><a id="admin" onclick="changeActive('admin');" class="active a red">Admin</a></li>
    <li><a id="dash" onclick="changeActive('dash');" class="a black">Dash</a></li>
    <li><a id="notifs" onclick="changeActive('notifs');" class="a black">Notifs</a></li>
</ul>

The idea is to change the active element dynamically.

My current function is:

function changeActive(id)
    {
      document.getElementById(id).className += "active a red";
      var c = document.querySelectorAll("ul a");
      for (i in c)
      {
        fav = c[i].attributes[0];
        if(fav.value!=id)
          {
            console.log(fav.value);
            document.getElementById(fav.value).className += "a black";
          }
      }
    }

Is there a more efficient solution to this? Thanks!

4
  • 1
    Using jQuery's addClass, removeClass would be a good alternative option Commented Mar 25, 2017 at 7:34
  • @ManivannanSadasivam—how is that more efficient? Commented Mar 25, 2017 at 8:12
  • What are your criteria for "efficient"? Faster? Less code? Commented Mar 25, 2017 at 8:13
  • @RobG To prevent looping (if possible) and to reduce lines of code. Commented Mar 25, 2017 at 8:14

6 Answers 6

8

Notice I removed += so that you donot end up adding same class every time.

function changeActive(id) {
      var c = document.querySelectorAll("ul a");
      var i;
      for (i in c) {
        c[i].className = 'a black';
      }
      //update it at last
      document.getElementById(id).className = "active a red";
}
Sign up to request clarification or add additional context in comments.

2 Comments

This is interesting. How can I limit the querySelectorAll() function to just my ul id="menu" ?
use querySelectorAll('#menu a')
3

Use classList property and it's add method. remove will remove the class

  document.getElementById(id).classList.add("active a red");

1 Comment

Thanks! But, I get this error in my console: The token provided ('active a red') contains HTML space characters, which are not valid in tokens
3

With navmenus, you want to set the active state on the li and apply the style to the a within the active li.

The following has both the id, the active class and the onclick handler in the li ( as well as a fake href in the a) and functions to remove the active class from all li's on the click and then apply it to the selected li. The .active class CSS then colors the a in red.

function changeActive(option){
  var option = option;
  var li = document.getElementsByTagName("li");
  for(i=0;i<li.length;i++){
     li[i].classList.remove("active");
  }
  document.getElementById(option).classList.add("active");
}
ul{list-style:none}
a{color:black;text-decoration:none}
.active a{color:red}
<ul id="menu">
    <li class="active" onclick="changeActive('admin')" id="admin"><a  href="#">Admin</a></li>
    <li onclick="changeActive('dash')" id="dash"><a href="#">Dash</a></li>
    <li onclick="changeActive('notifs')" id="notifs"><a href="#">Notifs</a></li>
</ul>

1 Comment

Thanks for a complete answer! It's interesting to see the use of CSS here to solve the problem!
2

If "efficient" means with the least amount of work for the browser to do, then the following may qualify. It has no loops and 3 lines of code.

You seem to want to change the class the clicked on element and remove it from any others that have that class. If you pass this from the click listener you don't need getElementById. If the listeners are added using addEventListener, then this is set to the element so you don't have to pass it.

And if you use querySelector you get straight to the element that already has the particular class so:

function changeActive(evt) {
  // Get the current "active" element
  var active = document.querySelector('.active.a.red');
  // Make it not active
  active.className = 'a black';
  // Set the clicked on element to active
  this.className = 'active a red';
}

// Add listeners when the load event occurs
window.onload = function(){
  Array.prototype.forEach.call(document.querySelectorAll('#menu a'), function(a) {
    a.addEventListener('click', changeActive,false);
    console.log(a.attributes[1].value)
  });
};
.active {
  color: red;
}
<ul id="menu">
    <li><a id="admin" class="active a red">Admin</a></li>
    <li><a id="dash" class="a black">Dash</a></li>
    <li><a id="notifs" class="a black">Notifs</a></li>
</ul>

I don't think it's sensible to use for..in over a host object where you really don't know what you're going to get. It's also not a good idea to assume that the first attribute is the id. If you want the id, get it directly using the id property.

Comments

1

Please check the below code,
HTML:

<ul id="menu">
    <li><a class="active a red">Admin</a></li>
    <li><a class="a black">Dash</a></li>
    <li><a class="a black">Notifs</a></li>
</ul>

jQuery:

$( document ).ready(function() {
    $('#menu li a').on('click', function() {
        $('#menu li a').removeClass().addClass( "a black" );
        $(this).removeClass().addClass( "active a red" );
    });
});

reduced HTML code, reduced JS code, no loops, no ID references to the elements, easy to understand. jQuery elements reference works same as CSS.

Note: Please dont forget to add jQuery library.

Comments

0
 document.getElementById(id).setAttribute("class", "class-name");

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.