jQuery Tip #1 – Defining a Context When Using Selectors
I really enjoy working with jQuery and have had the opportunity to use it a lot over the years on various projects. It’s an essential part of my “technology tool belt”. My company has also started providing new training classes on jQuery to various companies and I’ve had a lot of great questions come up about best practices, tips and tricks, when certain functions should be used over other functions, and more.
I decided to put together a series of posts that highlight simple tips and tricks that I’ve used in jQuery applications over the years to provide some guidance to developers new to jQuery and provide answers to different questions I’ve been asked. In this first post I’ll cover an oldie but goodie tip – defining a context when using selectors. It’s something I struggled with when I first started using jQuery but once I found the secret (which is quite easy) it changed how I used selectors and how I used CSS classes in my HTML.
Defining a Context when using Selectors
Selectors are an essential part of jQuery that provide a great way to locate nodes in the DOM quickly and easily. For example, the following selector can be used to find all div elements with a class of panel on them in a page:
var panelDivs = $('div.panel');
Selectors are well documented at http://api.jquery.com/category/selectors so I won't rehash what they are or how to use them here. However, I do want to mention one simple yet powerful tip that many people new to jQuery will find useful. It's one of the tips that I've ended up using over and over as I build applications. To demonstrate the technique let’s walk through a simple example.
Selectors can be used in the following way to find all elements with a class of panel on them:
var panels = $('.panel');
However, what if you want to grab all elements with a panel class that are children of a given parent container element? To better understand the scenario, consider the following HTML:
<div id="emailContainer"> <div class="panel"> …
</div> <div class="panel"> …
</div> </div> <div id="ordersContainer"> <div class="panel"> …
</div> <div class="panel"> …
</div> </div>
Assume that you already have a reference to the emailContainer div stored in a variable named emailDiv:
var emailDiv = $('#emailContainer');
How do you find all div elements with a panel class on them within the emailDiv element as opposed to finding every one within the page? One technique is to use the jQuery find() function:
var panels = emailDiv.find('div.panel');
You can alternatively supply a context object to the selector as shown next. This is the technique I normally use mainly because it’s something I’ve used for quite awhile (and old habits are hard to break).
var panels = $('div.panel', emailDiv);
Which way is the best? It depends on who you talk to although you can check out some live performance tests at http://jsperf.com/jquery-find-vs-context-sel that infer that find() has a slight performance advantage. Regardless, knowing how to supply a context when using selectors is a great technique to understand and useful in many different scenarios.
My development team has been using this technique a lot in an application that has several panels with a consistent set of CSS classes defined on elements within each panel. We’re using a plugin that we need to dynamically re-size as the panel changes size and created a function called refreshPanel() that accepts the panel to refresh. The object passed in to the function is used as the context for several selectors (it’s a jQuery object) to identify a starting point for searching elements with specific CSS classes. Here’s a section of a JavaScript file that defines refreshPanel().
...
refreshPanel = function (panel) { var padding = 5; //Handle height if (panelHeight == null) { toolbarH = $('.toolBar', panel).height(); tableHeadH = $('.clientDataTable', panel).height(); maxHeight = $(window).height(); panelHeight = (maxHeight / panels.length) - toolbarH - (tableHeadH * 2); } //Grab panel's current height var h = panel.height() - toolbarH - (tableHeadH * 2); //If panel's height is greater than the original panelHeight assigned in "if" above then they're maximizing var newHeight = (h > panelHeight) ? maxHeight - toolbarH - (tableHeadH * 2) : panelHeight; var w = panel.width(); $('div.dataTables_scrollBody', panel).height(newHeight - padding).width(w); $('.dataTables_scrollHeadInner, table.clientDataTable', panel).width(w); }
...
Notice that the panel object is used throughout as the selector context which allows the function to be re-used over and over for multiple panels. We use this technique in several places which allows us to consistently use the same CSS classes over and over within a given panel.
Conclusion
This is the first tip in a series I’ll be writing about jQuery. Although this tip is simple (and hopefully something you already know about if you’re an experienced jQuery developer), it’s very useful in many real-world situations.