Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

add a class to an `<a>` tag based on a comparison with an `<li>` class name

I just starting with javascript and jQuery and still learning syntax. I am trying to accomplish something that seems pretty complicated and was hoping maybe someone could help.

I am trying to add an "active" class to a top menu tab's <a> tag if the user is on any of the sub pages containing that tab's associated sidebar menu.

Each topmenu tab has its own sidemenu and the same sidemenu appears on all of its associated pages.

Each sidemenu has a unique classname assigned to its <li> tags that identify which topmenu tab it is associated with.

I assume this has to be initiated by a onLoad or something on the new page so I can't use 'this.' to refer to the parent topmenu tab.

I think what I need to do is get the href value of each ul.topmenu li a, with the / stripped out. (i.e. /kitchen, /park, /market becomes kitchen, park and market)

I think I can do it with something like this maybe?:

var hrefs = $("ul.topmenu li a").attr('href');
hrefs = hrefs.replace("/","")

Then I need to see if the class exists in ul.sidemenu li.[classname] (i.e. class="active-trail first odd sf-item-1 sf-depth-2 park sf-no-children")

maybe?:

$("ul.sidemenu li").hasClass('hrefs')

If a match is found I need to add "active" to the class for the "ul.topmenu li a"

maybe?:

$("ul.topmenu li a").addClass("selected");

I am sure there is a good way to do this. Am I even close? Any help is appreciated.

Edit:

This is the HTML for my topmenu:

<ul id="superfish-1" class="sf-menu main-menu sf-horizontal sf-style-default sf-total-items-6 sf-parent-items-0 sf-single-items-6 topmenu">
<li id="menu-218-1" class="first odd sf-item-1 sf-depth-1 topmenu sf-no-children"><a href="/" title="" class="sf-depth-1 topmenu">Home</a></li>
<li id="menu-456-1" class="active-trail middle even sf-item-2 sf-depth-1 topmenu sf-no-children"><a href="/park" class="sf-depth-1 topmenu active">Park</a></li>
<li id="menu-549-1" class="middle odd sf-item-3 sf-depth-1 topmenu sf-no-children"><a href="/farmstay" class="sf-depth-1 topmenu">Farmstay</a></li>
<li id="menu-574-1" class="middle even sf-item-4 sf-depth-1 topmenu sf-no-children"><a href="/market" class="sf-depth-1 topmenu">Market</a></li>
<li id="menu-580-1" class="middle odd sf-item-5 sf-depth-1 topmenu sf-no-children"><a href="/kitchen" class="sf-depth-1 topmenu">Kitchen</a></li>
<li id="menu-352-1" class="last even sf-item-6 sf-depth-1 topmenu sf-no-children"><a href="/galleries" title="" class="sf-depth-1 topmenu">Galleries</a></li>
</ul>

This is the HTML for the sidemenu shown on the pages under "Park" mainmenu link:

<ul id="superfish-2" class="sf-menu main-menu sf-vertical sf-style-default sf-total-items-5 sf-parent-items-0 sf-single-items-5 sidemenu">
<li id="menu-561-2" class="first odd sf-item-1 sf-depth-2 park sf-no-children"><a href="/park/activities" class="sf-depth-2 ">Activities</a></li>
<li id="menu-562-2" class="middle even sf-item-2 sf-depth-2 park sf-no-children"><a href="/park/facilities" class="sf-depth-2 ">Facilities</a></li>
<li id="menu-550-2" class="middle odd sf-item-3 sf-depth-2 park sf-no-children"><a href="/park/hours" class="sf-depth-2 ">Hours</a></li>
<li id="menu-564-2" class="middle even sf-item-4 sf-depth-2 park sf-no-children"><a href="/park/rules" class="sf-depth-2 ">Rules (there are always some)</a></li>
<li id="menu-563-2" class="last odd sf-item-5 sf-depth-2 park sf-no-children"><a href="/park/volunteers" class="sf-depth-2 ">Volunteers</a></li>
</ul>

Edit 2:

Okay, I think I am close. I switched to pulling from the URL, don't know why I didn't think to do it before, it should be much easier and doesn't require special attribute settings. It is not working yet, but here is what I have:

<script type="text/javascript">

   $(document).ready(function() {

     //split the url into parts 
     //www.greenwoodhill.com/park/activities should become an array of [greenwoodhill.com, park, activities]
    var a = location.pathname.split("/");

    //make sure there are at least 2 parts
    if ( a.length > 2 ) {
      //get the second section of the url
      //should be "park" in this case
      var page = a[2]

      // for each url in the .topmenu
      $('ul.topmenu li a').each(function(){

         // check if the href ends with /<page> and assign the class if so
         if ( this.href.substr( -page.length -1) === '/' + page){
           $(this).addClass('itworks');
         }

       });

     }

  });

</script>
like image 764
Jeramy Avatar asked Nov 18 '25 01:11

Jeramy


1 Answers

Update in regard to the updated answer

Your code is correct as a concept, but you have a couple of mistakes in execution ...

  1. location.pathname docs returns the path without the domain.
    So in your case it would be '/park/activities'

  2. That would be splitted to ['','park','activities'].
    To avoid the confusing empty first element you should us the .substr() docs method to remove the 1st / before splitting.
    This results to location.pathname.substr(1).split("/"); which will return ['park','activities']

  3. Arrays in javascript are 0-bazed docs, which means that the first element has an index of 0 (and not 1, as you might think)

  4. Now that we have cleaned the array from the empty element and we should check for a.length > 1 and since we need the 1st element (index of 0) we would access it with a[0].

  5. I added .toLowerCase() docs to make the comparison case-insensitive..

All combined it results in

var a = location.pathname.substr(1).split("/");

//make sure there are at least 2 parts
if (a.length > 1) {
    var page = a[0].toLowerCase();

    // for each url in the .topmenu
    $('ul.topmenu li a').each(function() {

        // check if the href ends with /<page> and assign the class if so
        if (this.href.substr(-page.length - 1).toLowerCase() === '/' + page) {
            $(this).addClass('itworks');
        }

    });
}

Working example at http://jsfiddle.net/gaby/gSxJc/


Original Answer

Assuming that the classnames of the .sidemenu match the urls of the .topmenu you can

// extract the classname from the first '.sidemenu li' element
var classname = $('ul.sidemenu li')[0].classname;

// for each url in the .topmenu
$('ul.topmenu li a').each(function(){
    // check if the href ends with /<classname> and assign the class if so
    if ( this.href.substr( -classname.length -1) === '/' + classname){
        $(this).addClass('selected');
    }
});

Update

since you create the .sidemenu manually, you should add a data- attribute to it and give it the value you want to use, to avoid searching through classnames ..

Something like

<ul id="superfish-2" data-page="park" class="sf-menu main-menu sf-vertical sf-style-default sf-total-items-5 sf-parent-items-0 sf-single-items-5 sidemenu">

and now instead of searching for the classname you can do

var page = $('ul.sidemenu li').data("page");
// for each url in the .topmenu
$('ul.topmenu li a').each(function(){
    // check if the href ends with /<page> and assign the class if so
    if ( this.href.substr( -page.length -1) === '/' + page){
        $(this).addClass('selected');
    }
});
like image 151
Gabriele Petrioli Avatar answered Nov 19 '25 16:11

Gabriele Petrioli