Tag: UI

Showing and Hiding Content By Clicking A Menu Link (jQuery Tutorial)

While working on the user interface of the WordPress Plugin I’m building, I needed to have something akin to a drop down menu. A user clicks on a menu item, and a related list appears elsewhere on the page (in my case it’s a tool menu). To achieve this functionality I first looked at existing jQuery scripts and plugins and considered Superfish, which I was already using for the tab navigation. Using multiple instances of Superfish on the same page didn’t look as straightforward as it should be so I looked to build my own jQuery script, how hard could it be?

On my first attempt I worked with my limited jQuery knowledge and wrote a lot of code. It worked, it was logical but I knew I wasn’t being efficient. One of the most common mistakes for beginners to jQuery is to assign click handlers more generously than needed. My first attempt resulted in a lot of redundant code – I had assigned click handlers to every link in the menu.

Later I revisited my first attempt (which did work) and went about refactoring the code to get something more efficient. My secondary goal was to lose the need for Superfish on my other tab nagivation as well. My first step was to apply event delegation properly. Instead of assigning click handlers to each link in the menu, I assign a handler to the menu. There are a couple of functions to achieve that in jQuery, such as click(), bind(), live(), delegate() and on(). They all have their own merits and optimal use cases. On() seemed the most attractive to me for my interface, but since it has only recently been introduced in jQuery 1.7 I’m using delegate() in my plugin since the current WordPress ships with an older version*. I’ll show how it works for both, since the difference is minimal.
* WordPress 3.3 will come with jQuery 1.7

with delegate():
[javascript]
$(“#divtoggle”).delegate(“a”,”click”, function(e) {
// do stuff
});
[/javascript]
with on():
[javascript]
$(“#divtoggle”).on(“click”, “a”, function(e) {
// do stuff
});
[/javascript]

#divtoggle is the id assigned to the menu containing the links. In my case, the menu with the links are separate from the content I want to show on a mouse click. I have the content in a separate div lower on the page, hence giving the menu the id of divtoggle. As a sidenote, you might be wondering why I´m using ID attributes. On my first attempt, I gave my elements classes to make it easy to target them with CSS styling and jQuery. If you have an element you need to specifically identify with jQuery/Javascript, it´s more efficient to select it based on an ID compared to a class name. The ID attribute is meant to be a unique identifier, which means there will be only one element on the page with that specific ID. If you have to search through a document looking for an ID, you can stop as soon you found it, if you´re looking for an element with a certain class, you have to go through the entire document because there may be multiple elements with that class name.

Here is example HTML markup of the scenario.:

[html]

This is the content inside the first container

This is the content inside the second container

This is the content inside the third container

[/html]

The links also have unique ID’s as this will give me a way of linking the id to the container.
[html]show div 1[/html]

What we want to have happen is to recognize when a link inside the menu was clicked and then ascertain what link it was. We can grab the id of the link that was pressed and then use it to identify what container to show. We can use the prop() function to get the ID properity of the link.

[javascript]
$(“#divtoggle”).delegate(“a”,”click”, function(e) {
// get the ID of the clicked link
var toggled = ($(this).prop(“id”));
});
[/javascript]

Now we know what link has been clicked there are a number of ways to set the visibility of our div content. In this scenario, I wanted to have only one of the three containers displaying at the same time. On my first attempt, I was assigning a css class directly to the div containers that toggled their visibility. I found this a little laborious, as you have to assign and remove classes for each of the relevant div containers. On my second attempt, I decided to simply set a class for the parent container, which in the example is the div with the ID ‘wrap’. In the CSS, we can then set the visibility of the div containers based on the class of the parent container.

[css]
// hide menu related content by default
#div1, #div2, #div3 {
display:none;
}
// display content related to menu item
.togglediv1 #div1, .togglediv2 #div2, .togglediv3 #div3 {
display:block;
}
[/css]

Now in our jQuery, we assign a class to the parent div container based on the link that was pressed.

[javascript]
$(“#divtoggle”).delegate(“a”,”click”, function(e) {
// get the ID of the clicked link
var toggled = ($(this).prop(“id”));
// assign the value of the link id as a class to the parent container
$(“div#wrap”).prop(“class”, toggled);
});
[/javascript]

Basically this is what happens when you click the first link in the menu:

1) menu link was clicked
2) the link had the id ‘togglediv1’
3) the class of ‘togglediv1’ was set to the ‘div#wrap’ element, which automatically makes the appropriate div content display because of our CSS rules.

Check the DEMO on jsfiddle.net.