jQuery ‘drop down’ sub-menus for Expression Engine’s category module

August 26, 2009

See the live example in the sidebar of the Navigenics blog.

Today I cleaned up a huge category list on the sidebar of Navigenics’ blog. Since the main problem we were trying to solve was to free up some side bar real estate, I was asked ‘is it hard to put those into a drop down thing?’ We decided on having main category headers and then nesting sub-categories within them. I gave it a shot using the power of jQuery and I am happy with the results.

We use the default “categories” module in Expression Engine, which does not give you much flexibility in terms of how the markup is output without mucking with the php or extending it with a plugin. This solution allows you to keep using the default category manager and simply use a bit of javascript to bend it to your will. From the admin interface of EE, in the category manager, set up your sub categories.

Set up sub-categories in Expression Engine

Example:
Picture 11

This will create html markup that looks like this:

<ul class="nav_categories" id="nav_categories">
    <li>
        <a href="/category/conditions_we_test/">Conditions we test</a>
        <ul>
            <li><a href="/category/crohns_disease/">Crohn's disease</a></li>
            <li><a href="/category/breast_cancer/">Breast cancer</a></li>
        </ul>
    </li>
    <li><a href="/category/diabetes/">Diabetes</a></li>
    <li><a href="/category/exercise/">Exercise</a></li>
    <li><a href="/category/for_physicians/">For physicians</a></li>
</ul>

To get the drop-down functionality I need, I want to add classes to the parent category’s <li> and <a> tags so that I have hooks for my css and javascript:

<ul class="nav_categories" id="nav_categories">
    <li class="sub-cat-heading">
        <a class="cat-expander" href="/category/conditions_we_test/">Conditions we test</a>
        <ul>
            <li><a href="/category/crohns_disease/">Crohn's disease</a></li>
            <li><a href="/category/breast_cancer/">Breast cancer</a></li>
        </ul>
    </li>
    <li><a href="/category/diabetes/">Diabetes</a></li>
    <li><a href="/category/exercise/">Exercise</a></li>
    <li><a href="/category/for_physicians/">For physicians</a></li>
</ul>

Since we can’t control the markup enough with the default category module in EE, we do some jQuery dom traversing and add the classes with javascript:

Add classes using jQuery

$('.nav_categories li')
    .children() //get all the children 
    .find('li') //find only the ones that are li's
    .parent('ul').hide() //of the li's you found hide that ones that have ul's for parents (means they are sub-navs)
    .parent('li') //The proud parent of the nested ul(which is a li) example--><li><ul>
    .addClass('sub-cat-heading') //give the li a name in the form of a class
    .find('a:first') //get the link that is now becoming a heading
    .addClass('cat-expander'); //give that link a name so we can target it specifically it later

This will give us the proper markup we wanted, now we add the little arrows, and the magic for the functionality.

Add some css

If you are trying to copy this exactly you will need the drop down arrow gif, or make your own.

.nav_categories li.sub-cat-heading {
    background:none;
}
 
.nav_categories li.sub-cat-heading a.cat-expander{
    background: url(/assets/images/drop_arrows.gif) no-repeat right -8px;
    padding-right:14px;
}
 
.nav_categories li.sub-cat-heading a.open{
    background-position: right 5px;
}

The final jQuery js with the drop down action

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
 
var subCatDropdownEE = {
 
    init:function(){
 
        $('.nav_categories li')
            .children() 
            .find('li') 
            .parent('ul').hide() 
            .parent('li')
            .addClass('sub-cat-heading')
            .find('a:first')
            .addClass('cat-expander')
            .click(function(event){ //click action on the link that has now become a clickable drop-down heading
                $(this)
                .toggleClass('open') //toggle adding a 'open' class to know which way to point the arrow
                .parents('li:first')
                .find('ul') //find the ul that we hid up above
                .slideToggle(); //slide it open if its closed, closed if its open
 
                event.preventDefault(); //prevents the link from being a link, since its now just a trigger for our drop-down
            });
    }
}
 
subCatDropdownEE.init();
 
});
 
</script>

I hope some ExpressionEngine peeps find this useful. Peas out.

Comments (5)

  1. MIchael LeHewAugust 27, 2009

    Interesting post. I think it has value outside of EE in any situation where you don’t have full/any control of the markup.

    Also, I wonder if there is a way to tighten some of those chained searches to improve performance, don’t have time at the moment, but it seems like it might be possible.

  2. Twitter Trackbacks for jQuery ‘drop down’ sub-menus for Expression Engine’s category module [building58.com] on Topsy.comAugust 28, 2009

    [...] link is being shared on Twitter right now. @ee_hub, an influential author, said jQuery ‘drop down’ [...]

  3. chloramphenicol onlineSeptember 17, 2009

    Speak slower louder, quieter,

  4. Jose B. RiveraFebruary 14, 2010

    I tried this and it did work. I put the javascript right below the body tag, the css in the css page and the code right on the and and it came out already expanded and it did not collapes. Did I do something wrong.

  5. jorgeApril 8, 2010

    very helpful.. thanks

Add a Comment