Search code examples
jqueryajaxhashchange

Add "active" class to current menu item by detecting path after hash (#)?


My website uses a hash in its URL to navigate with AJAX (which I got from this tutorial). When a link is clicked, a /#/(link name) is added to the end of the url.

If I'm at mysite.com, and I click on "photos", the url becomes, mysite.com/#/photos, and the "#content" div is re-populated with the #content div from /photos.

Also, if for some reason, the user manually types "mysite.com/photos", and then clicks on "bio", his URL will look like "mysite.com/photos/#/bio"

The fact that the page does not re-load, and that the URl does not EXACTLY match the href in the menu a tag, is making it hard for me to figure out how to add an active class to the current menu item.

my menu is generated by wordpress, and looks like this

<div id="main-menu">
<ul>
<li><a href="mysite.com/photos">Photos</li>
etc.
</ul>
</div>

Please help!


Solution

  • I'm guessing that in mysite.com/photos/#/bio you want to set active to the bio link? In other words, the last "word" of the url.

    To achieve this, you can do something like this:

    var path = window.location.pathname.split("\/"), myString;
    
    if(path[path.length-1] === "")
        myString = path[path.length-2];
    
    else
       myString = path[path.length-1];
    
    myString = myString.toLowerCase()
    console.log(myString);
    

    The if/else check is there because if the pathname is "/hola/bandola/" the last element in the array after split will be an empty string, but if it's just "/hola/bandola", "bandola" will be the last item. So to make it work with both ways the check is necessary. Now you have that variable with the right string and can set the right link to active with that information.

    EDIT: Since you don't generate the navigation links dynamically, you'll have to compare the value you got from my code to something unique for each navigation link. My suggestion is that you add a data-attribute in the a-tags that would match the string you got from my code. Example: <li><a href="mysite.com/photos" data-page="photos">Photos</li>

    Now you go through each a-tag in the UL and compare the data-page values to the value you got from the querystring, and set class to "active" if they match:

    var links = $("#main-menu").find("a");
    $.each(links, function() {
             if($(this).data("page") === myString)
                 $(this).addClass("active");
    }​);​
    

    ​​​You could just have compared the text within the a-tags, but if the text doesn't match the url-string, that wont work, so it's better to add a data-attribute. Note that I edited the code above to make sure the "myString" variable is lowercase when comparing to the data-attributes. Hope you understand.

    EDIT2:

    To compare the text inside the a-tag instead, use this each loop instead:

    var links = $("#main-menu").find("a");
    $.each(links, function() {
             if($(this).html("page").toLowerCase() === myString)
                 $(this).addClass("active");
    }​);​