Last month, I introduced several jQuery tips that can enhance code performance, handle events in different ways, and simplify maintenance. Here I'll continue with the theme of jQuery tips and tricks and cover a new batch of four more ways to improve your jQuery coding productivity. Let's start out by talking about a lesser-known function in jQuery called end() and how it can be used when you're manipulating the Document Object Model (DOM).

Checking Whether a Node Exists

This first tip is very straightforward and one that I've used a lot over the years. I've found that many developers new to jQuery waste time looking for a built-in function (I know I did) that checks whether a node exists, so I thought this tip would be worthwhile to cover.

There are times when you need to know whether or not a node exists in the DOM. You don't necessarily need to modify the node or add anything to it, just determine whether it exists. Although you won't find a function such as exists() in jQuery, you can check the length of the selector you use to determine a node's existence. The following code shows how to do this:

if ($('#myDiv').length > 0) {
    alert('Node Exists!'):
}

Because 0 equates to false in JavaScript, this code can be simplified to the following, if you like:

if ($('#myDiv').length) {
    alert('Node Exists!'):
}

Of course, you really don't need jQuery at all to perform such a simple task. The following code performs the same task and has less overhead. Sometimes thinking outside of the jQuery bubble is a good thing.

if (document.getElementById('myDiv)) {
    alert('Node Exists!');
}

Using end() to Work with Sets

jQuery's selector functionality makes it easy to add new nodes into the DOM without making a lot of calls to document.createElement(). For example, the following code adds <div> and <span> nodes into the DOM and appends them to a divContainer node:

$('<div class="cust"><span /></div>').appendTo('#divContainer');

The first part of the code -- before appendTo() -- creates an initial set and adds it to the stack. After the set is on the stack, you can go into it and use find() to grab specific nodes, as shown next:

$('<div class="cust"><span /></div>')
  .find('span')
    .html(custName) //Update with some dynamic variable
  .appendTo('#divContainer');

Once find() is invoked, you're on the <span> node, so the node will be appended to divContainer instead of the <div> that wraps <span>.

In cases where you need to dynamically generate DOM nodes, modify specific children as with the <span> shown in the previous example, and then append the entire newly created set into a container, what can you do? Fortunately, jQuery provides an end() function that allows you to pop the current set off the stack and then move down to the next one. In the previous example, calling end() immediately before appendTo() would cause the initial <div> that wraps <span> to be appended to divContainer, which would probably be a desirable behavior in this case.

Figure 1 shows an example of using find() and end().

$(document).ready(function () {
    var custs = getCustomerData();

    for (var i = 0; i < custs.length; i++) {
        var cust = custs[i];
        $('<div class="cust"><span /></div>')
            .find('span') //get to span
                .attr('title', cust.City)
                .data(cust)
                .html(cust.Name)
                .click(showCust)
            //.end() //get back to span's parent div
            .appendTo('#divContainer');
    }
});

The code starts by creating the <span>, which adds a new set to the stack. The code then moves to the <span> using find() and modifies an attribute, the inner HTML, and the data associated with the node. Finally, the code calls end() to move back to the wrapper <div>, then appends it to divContainer.

What's convenient about this type of code is that you can create a span, hook up some data to it (via the data() function), and then append the parent of the <span>, all in one step. Although there are certainly other ways to accomplish this task, end() can be handy when you need to chain several functions together.

Cache jQuery Selectors Whenever Possible

One of the best, and simplest, tricks in the jQuery book is to take advantage of selector caching anytime you can. I've seen a lot of code in which developers scatter the same jQuery selector throughout code, not realizing that they could simplify their code and potentially increase performance by caching the selector. Here's an example:

for (var i=0;i<10;i++) {
    $('#containerDiv').append('<span>' + i + '</span>');
}

This causes the divContainer node to be looked up 10 separate times. Although ID selectors are very fast, the code could be made more efficient by finding the divContainer node outside of the loop, storing it in a variable, then referencing it in the loop, as shown next:

var $div = $('#containerDiv');
for (var i=0;i<10;i++) {
    $div.append('<span>' + i + '</span>');
}

This example starts by caching the containerDiv node in the $div variable. The variable is prefixed with $ to make it easy to see that it's a jQuery wrapped object as opposed to a raw DOM object -- a popular trend in some circles. The variable is then used within the loop to append <span> children to it. The end result is that only one lookup is done for containerDiv as opposed to 10.

Note: You can enhance the performance of this code even further by eliminating DOM manipulation code in the loop. Refer to the first article in this series for a discussion about techniques that can be used in loops as well as general performance results.

Create a Custom jQuery Selector

Selectors are a key part of jQuery and one of the features that have made it so popular over the years. If you've worked with jQuery, you've used different types of native selectors, including tag name, ID, class name, and others. jQuery also provides selector extensions that add the ability to search children in a given parent by position, locate input elements, find even or odd elements, and much more. A few examples of custom selector extensions in jQuery are :eq(), :hidden, :gt(), and :visible; you can find the complete list of the selector extensions built into jQuery here.

Although most jQuery developers know about selector extensions, many aren't aware that you can write your own custom selectors quite easily. Although custom selector extensions certainly aren't required, they can be useful in situations when you find yourself writing the same type of code over and over and you want to simplify things as much as possible. For example, assume that you have the divs shown in Figure 2 defined in a page and you'd like to write code to display all hidden divs. This code is a bit contrived in order to demonstrate a point; I'd stick with consistently using Cascading Style Sheets (CSS) class names in a real app.

<div class="panel hidden">
    Panel 1
</div>
<div class="panel" style="visibility:hidden">
    Panel 2
</div>
<div class="panel" style="display:none;">
    Panel 3
</div>
<div class="panel">
    Panel 4
</div>

If you wanted to show all panels that have the hidden class on them or those that have a style of display:none or visibility:hidden set, you might write code similar to that shown in Figure 3. This code is run as a button that's clicked in the UI.

$('#showPanelsButton').click(function () {
    $('.panel').each(function () {
        var $pnl = $(this);
        if (($pnl.css('display') == 'none') ||
             $pnl.css('visibility') == 'hidden' ||
             $pnl.hasClass('hidden')) {
            $pnl.removeClass('hidden')
                .css({ 'display': '', 'visibility': '' });
        }
    });
});

Although there's nothing wrong with this code, if you find yourself needing it in multiple places, you'll either refactor it into a function (the preferred approach) or copy it around throughout one or more scripts. Alternatively, you could write a custom selector that lets you encapsulate the code into a reusable function and use it directly within your jQuery selectors.

To create a custom selector, you use jQuery's extend() function, defining the expression that needs to be extended (the : character, in this case), and then associating a selector name with a function that determines what nodes are included in a set and what nodes are excluded as the custom selector is used. This may sound a little complex at first, but it's surprisingly simple once you see the pattern. Figure 4 shows how the code in Figure 3 can be refactored within a custom selector.

$.extend($.expr[':'], {
    hiddenPanel: function(pnl) {
        if (pnl == null) return false;
        var $pnl = $(pnl);
        return $pnl.css('display') == 'none' ||
               $pnl.css('visibility') == 'hidden' ||
               $pnl.hasClass('hidden')
    }
});

Looking through the code in Figure 4, you'll see that we start by calling jQuery's extend() function, passing it the expression that we want to extend (: in this example), an object literal that defines the custom selector name, and the function that will be called once the selector is executed. In this example, the custom selector is named hiddenPanel. When this custom selector is used in a jQuery selector, the function will check whether the node that is passed in has its display set to none, has its visibility set to hidden, or has a CSS class on it named hidden. If any of the conditions are met, the node is included in the set and returned to the caller. If the node doesn't meet any of the conditions, it will be excluded.

The code in Figure 5 demonstrates how to use the hiddenPanel custom selector.

$('#showPanelsButton').click(function() {
    $('.panel:hiddenPanel')
        .removeClass('hidden')
        .css({ 'display':'', 'visibility':''});
});

Note that :hiddenPanel is now available to use anytime you're working with selectors. This custom selector makes it a straightforward process to look for hidden panels, get a set of nodes that match the conditions defined in the selector, and then modify the nodes. Although this simple custom selector example may not necessarily apply to your own application, knowing how custom selectors can be created and used can be handy in a variety of scenarios.

Coding Productivity Aids

The jQuery tips and techniques I've covered here and in the previous article in this series can help minimize the amount of code you have to write, enhance performance, and refactor your code to make it more reusable in some situations. There are many more tips that can be covered, but for developers who are getting started with jQuery, the tips provided in these two articles can jump-start your jQuery learning process. Now that you know how to write basic HTML5 and jQuery code, we'll delve into how you can utilize these tools to jump start your web development projects in "Start Using HTML5 in Your Web Apps - Today!"