Although I’ve been taken by jQuery’s impressive API and all the discussion about it, there’s been limited need for me to really go in depth because I’m quite good with DOM manipulation routines and really, how can you go much faster than var target = document.getElementById(‘targetID’) ? Another angle here is that, having not known about jQuery through my learning curve of Javascript, I developed a way of thinking that took care of speed and code readability without it.
But all that said, I’ve been keeping my eyes open for opportunities to use jQuery both for personal edification and because I do believe it can make life easier.
Now, over the course of the last several months there have been 3 distinct examples where my life has been made much easier with jQuery. So with that, it’s become fixture in my toolbox and something that will get more of my attention as needs warrant. What I’d like to do in this post is outline my 3 examples as clearly as possible, hoping both to enlighten other jQuery n00bs and to entice jQuery experts to chew up my methods and tell me how to do things better.
Unobtrusive Javascript and late-bound GUI effectsMy first real example is perhaps the most dramatic. I have a client with loads of web pages and loads of data on those pages. They wanted to make large blocks of those pages drop-downs, rather than huge scrollable pages. I’m not sure that it’s my favorite GUI design, but that’s immaterial here. From an SEO perspective, I did not want to damage our ranking or context at all by adding JavaScript or lots of crap to the content that Google would have to wade through. Consider the following HTML:
<div class=”pHead”>Lorem ipsum dolor sit amet</div>
<div class=”pBody”> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</div>
Now this could be done with P or any other number of CSS mechanisms, let’s not go into that here. The point is that I have multiple paragraphs, under the notion of a header, and the client wanted the header to be a drop-downable arrow rather than just huge, scrollable text. Additionally, there’s lots of this stuff on the site – and lots of folks involved in the content, certainly not just me. I needed to give them a DIV structure they could work with and do the code part outside of the content. This is where the “Unobtrusive” part of this example comes into play.
My strategy was to bind the onClick event of appropriate DIVs to a little bit of code so that I could simply change classes or styles of the content to create the effect. So my jQuery code will jump on the Page Complete event, looking for certain DIVs, vector their events to (me) and then use jQuery’s native functions to effect the transition as attractively as possible.
My solution was to wrap a “droppable” element into a new div, which I could style. Consider:
<div class=”pChunk”>
<div class=”pHead”>Lorem ipsum dolor sit amet</div>
<div class=”pBody”> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
</div>
</div>
The code is incredibly small. There are only 3 parts here: the code that jumps on the page-ready event, the function that binds onMouseOver, onMouseOut and onClick and the actual collapse logic:
function collapse(e)
{
var parent = e.target.parentNode;
var divs = parent.getElementsByTagName('DIV');
var target = $(divs[1]);
if (target.is(':visible'))
{
target.fadeOut('fast');
parent.style.backgroundImage = 'url(/graphics/rightTri.gif)';
} else {
target.fadeIn('fast');
parent.style.backgroundImage = 'url(/graphics/downTri.gif)';
}
}
function bind()
{
jQuery('.cChunk .pHead').bind('click', collapse).bind('mouseover mouseout', function(e) { e.target.style.textDecoration = (e.type == 'mouseover') ? 'underline' : 'none';} );
}
jQuery(function($) { bind(); } );
CSS file additions include:
.pChunk {
background-position: 0 3px;
background-image: url(/graphics/rightTri.gif);
background-repeat: no-repeat;
padding-left: 15px;
margin-bottom: 10px;
}
.pChunk .pHead {
cursor: pointer;
}
.pChunk .pBody {
display: none;
}
The last bit of code is what jumps at the page ready, and it calls the bind() function. The Bind function binds the click event for any element that has a class pHead that is a child of an element that has a class pChunk. Using jQuery’s chaining feature, I continue on to bind the mouseOver and mouseOut events to an inline function that changes the text-decoration of the sender to underlined if mouseOver, non-underlined if mouseOut. The chaining feature of jQuery is definitely cool.
Now then: Someone clicks on a pChunk div and the collapse function is called. The (e) parameter is the jQuery event object – it is more lush than normal event objects and it is standardized, regardless of browser. Essentially, I get all the DIVs that are children of the clicked-on DIV, and based on their visibility, I either fade them out or fade them in. As you can see from the CSS styling of the pChunk, I have room for a little graphic on the left-hand side. The default is a right-facing triangle. As the element is clicked, it changes to facing down (content visible) and facing right (content hidden).
The net-net is that I was able to have the content people do minimal work, in fact only wrap chunks they wanted droppable, and my code did all the rest. As a site-wide inclusion, it made it so that any pages they added the simple pChunk wrapper around a block of content instantly became a drop down.
You want a demo? Of course you do, everyone loves a demo.
CLICK HEREAlternating Gray Bars on Rows of ContentI must admit, I was completely //yawn// about having jQuery do color alternation for me. I mean really. I’m already creating the content in PHP server side, the CSS file contains the definition for both colored rows, what’s the big deal for me?
The answer came when I added a content manipulation tool for a client. This client has a restaurant and I create a chalkboard of “Today’s Specials” for him (some of you may remember where I posted about it in a thread here). What I added was a “Move Up” / “Move Down” feature to the menu manager. The problem was that as the content rows (whole DIVs) moved up or down, they took their coloration with them! So I was obliged to re-color rows.
And so, this simple example from the first book I read became a life saver:
$('.menu_menuBlock:even').addClass('gray');
$('.menu_menuBlock:odd').removeClass('gray');
This is really, deceptively cool. First off, for those that don’t know: jQuery uses the JavaScript macro, $ for brevity. You may use jQuery or $ interchangeably in my examples. There are some libraries that want to make use of $ so make sure you read up on that if you use other libs than jQuery. Anyhoo, that first little line, called right after any Move Up or Move Down button is clicked, says “create a wrapped set out of every element that has the class menu_menuBlock (I only use this on DIVs I want to do this to) – but only the EVEN number among them, not all. In other words, DIV 0, 2, 4, 6 etc. To those, add the class ‘gray’ – the next line removes the gray class from any odd items. In fact, experienced jQuerysters will tell you that there are even more clever ways to do this, but it is pretty obvious here. So now, the colored bars appear to stay, the content moves in them. It’s a great look and super efficient.
Moving DIVs in relationship to each otherMy last example is actually borne of frustration. I’d been trying to use the .prev() and .next() function in jQuery for several hours and just could not get them to work correctly. And here is my only complaint in this post about jQuery: it’s so big, so complicated and so powerful that it’s difficult to get your arms all the way around it, as well it’s difficult to know how to search for appropriate help with problems. I have several books on the subject, and a reasonably good Googler and nothing helped here. I am certain that I was doing something wrong, but it’s indicative of the nature of the package that I could not find an example or help with my problem. But I digress.
This example pertains to the same challenge I had in example 2: I want to move whole chunks of content above and below other chunks. Of course, my strategy is to simply reposition DIVs above or below their siblings. The appendBefore and appendAfter functions are particularly helpful here, because they will automatically do the parent change for me (In fairness, the DOM functions do the same, but it felt better here).
The code that comes from the AJAX handler sends back a DIV with the class “menu_menuBlock” and a bunch of stuff within it. The function that calls this is a button in each block with the onClick handler set to “menu_moveUp(this).” The handling code is as follows:
function menu_moveUp(sender)
{
var myBlock = $(sender).parents('.menu_menuBlock')[0];
var allBlocks = $('.menu_menuBlock', myBlock.parentNode);
var idx = allBlocks.index(myBlock);
if (idx == 0) return false;
$(myBlock).insertBefore(allBlocks[idx - 1]);
}
function menu_moveDown(sender)
{
var myBlock = $(sender).parents('.menu_menuBlock')[0];
var allBlocks = $('.menu_menuBlock', myBlock.parentNode);
var idx = allBlocks.index(myBlock);
if (idx >= allBlocks.size() - 1) return false;
$(myBlock).insertAfter(allBlocks[idx + 1]);
}
“Sender” is a commonly used name for the object that sent the event – and a throwback to my Delphi and Kylix days. Once again, I am certain that experienced jQuerysters will tell me I am FOS and that this is horribly inefficient – right then. I could use the help. But in the mean time, this is how that code works:
- myBlock is set to the zeroth entry in a wrapped set of all parents of the sender that have the class “menu_menuBlock.” In other words, no matter how deep the sender is in the DOM, that will walk up the hierarchy of parents to find (my) parent with the correct class.
- allBlocks becomes a wrapped set of all siblings, because of the way I did it: it looks for all elements that have the menu_menuBlock class WITHIN myBlock’s parent node. Note that this is an underused parameter in jQuery IMO: the second parameter locks jQuery to only looking for things that match param 1 within the context of param 2. This can REALLY make things faster, since you’re not looking through the entire DOM for something.
- idx gets the numeric index position of the “sender block” within it’s parent.
- The if () statement checks to make sure that this is a valid move. In the case of Move Up, if the sender’s index is 0 then there’s nowhere to move and the function returns without doing anything. In the case of Move Down, if the index is >= the size of the wrapped set then nothing happens.
- Finally, I put myBlock back into a wrapped jQuery set (so that I can do stuff to it) and call insertBefore or insertAfter, passing the new location where I want it to be.
After all of that, I re-color the blocks

jQuery still pisses me off a lot. It’s complicated and not nearly as straight forward as I would like. On the other hand, as I get used to thinking it its rhythm, I see more applications for it. Clearly, once I’ve paid the price for downloading it, I might as well use it rather than write scads of new code. It’s a pretty damn great tool and I look forward to using it more in the future. I also *really* get that it will be a keystroke saver, as well as potentially a processor saver in the future. I still believe that there is overuse and people relying on if for the wrong things, but I'll post on that another time.
Good luck with it. Please tell me where I am foolish and inefficient – I’d really like to know the tool better.