An Introduction to jQuery, Part 1 (Cont.) Another Simple Example Showing a Popup Window jQuery can also help to create utilitarian UI features. Let’s add a pop-up window to the example, and allow dynamically typing selectors that select and highlight matched elements in the entire page. The end result is shown in Figure 4.  Figure 4: Displaying a dynamic pop-up window with some effects.A user pops up the “dialog” by clicking the Show Query Dialog window, which “slides in” the dialog from the top of the page and displays it with a slightly transparent background on top of the page content. You can then type a jQuery selector in the text area and effectively apply it against the document. When you click the button, the selected elements are highlighted in dark red in the document and then removed after a few seconds. The dialog is stored on the page as a simple <div> tag element that’s styled and looks like this in markup: <div id="divjQueryDialog" class="blackborder"> <div class="gridheader"> Enter a jQuery Expression</div> <div class="containercontent"> Expression: <span id="lblExpressonMsg"> </span><br /> <textarea id="txtExpression" style="width: 300px; height: 60px;"> </textarea> <input type="button" value="Show" id="btnExpression" /> </div> </div>
There’s also some styling for the dialog that makes it transparent, initially hidden, and absolutely positioned on the page: #divjQueryDialog { width: 380px; position: absolute; left: 100px; top: 70px; display: none; }
The code that makes the panel visible, applies opacity, and handles the matching and selection is relatively simple too and shown in Listing 2. The code initially makes the div visible and applies opacity. It then hooks up a click handler to the button and an anonymous function to handle the processing of the click. That code captures the input text and then uses jQuery to “evaluate” the selector applying a special class to the matched set. The code also sets up a timeout that removes the highlight class after 5 seconds. I mentioned nesting anonymous functions earlier and the above code shows another example-the code above is quite asynchronous, yet it is written in a single block of code that keeps context. The inner click handler has access to the dialog without having to reselect it. This is due to the way JavaScript handles nested closures or function blocks, which can see private variables defined higher up in the function definition stack-even if the code is asynchronous. In this example this is trivial, but if the fade out code (or “class”) contained more state, it’s quite convenient to have the state passed to the handler merely by virtue of being declared inside of the parent closure. This type of coding can often be easier to read as it keeps relative logic together in one place. A couple of other things to highlight here: Notice the code to make the dialog transparent: dialog.hide() .slideDown("slow") .css("opacity",.90);
jQuery is smart about how it handles certain CSS tags that browsers handle differently, such as opacity. Internet Explorer doesn’t support the opacity style (because it’s not officially part of the CSS 2.1 standard), but jQuery automatically does the right thing applying a filter style for Internet Explorer. jQuery applies similar rules for other CSS properties and certain functions. For example, .text() retrieves text consistently and .scrollLeft/Top retrieves scroll position safely. So jQuery acts as a normalizer between different browser implementations. One last enhancement: If you want to make the window draggable so you can move it around the page, this is also easy to do using the draggable plug-in from jQuery UI. To use this plug-in, download jQuery UI and dump the library into your scripts folder (relevant portions provided in the sample). Then add: <script src="scripts/ui.core.js" type="text/javascript"></script> <script src="scripts/ui.draggable.js" type="text/javascript"></script>
To the page and simply add: var dialog = $("#divjQueryDialog"); dialog.draggable();
That’s it. You’ve just made your “window” a lot more window-like with a single line of code through use of the draggable plug-in. There are a number of options you can apply to draggable-for example to set the drag handle to the window’s header you can use: dialog.draggable({ handle: $("div.gridheader") });
which makes only the header initiate a drag operation, which is more natural window behavior. Plug-ins for Everything Else Plug-ins are one of the main reasons that jQuery has become so popular. Part of the reason for this is that jQuery has a super simple API for plug-ins. There is a jQuery.fn property which hosts any operational functions that can operate on the matched set. By simply implementing a new function on jQuery.fn you effectively create a new matched set function that works like jQuery’s built-in functions. Here’s a very simple pulse plug-in that pulses an element by fading it out partially and then fading back to full visibility: $.fn.pulse = function(time) { if (!time) time = 2000; // this == jQuery instance this.fadeTo(time,0.30, function() { $(this).fadeTo(time,1); }); return this; // return jQuery }
You can now simply use a jQuery instance and the pulse function on it to pulse matched elements. For example, earlier you added a new item to the grid-you can pulse this item instead of fading it in: row.insertBefore( "#gdEntries>tbody>tr:nth-child(2)") .css("background", "paleyellow") .pulse(2000);
This plug-in also works against many matched elements: $("#gdEntries>tbody>tr") .filter(":even") .addClass("gridalternate"); .pulse(1000);
which pulses only the even rows. A plug-in receives a this pointer that is the jQuery matched set. So you can apply further functionality to this matched set in the plug-in code. If the plug-in doesn’t have a distinct return value you should always pass the jQuery result set back as a return value so that the function is chainable for additional jQuery functions: $("#gdEntries>tbody>tr") .filter(":even") .addClass("gridalternate"); .pulse(1000) .addClass("small");
This plug-in is overly simplistic. More commonly you need a little bit of set-up data as well some logic to loop and manipulate the matched elements individually. Listing 3 shows another slightly more realistic plug-in that centers any elements in the browser window or inside of another element. This plug-in includes a couple of common patterns. First it has a set of option parameters that you can pass in as an object map (i.e., {container: "#divContainer"} ). Notice that opt is defined as a private variable and then extended with the option parameter object. $.extend() is a wonderful utility function that extends an object with the content of another object. This makes parameter processing easy for the user, by passing in only the parameters you are interested in. Most plug-ins accept options parameters in this fashion and it’s a good idea to implement options in your own plug-ins. The next common plug-in pattern is to return this.each( function() {…}); which ensures the jQuery matched set is returned. The .each function iterates through each of the matched DOM elements individually and lets you operate against each of them one at a time. Inside of the .each() function handler, the this pointer is always the DOM element iterated over. You can use $(this) to get a jQuery instance for that element, which is typically what you want to manipulate the element. Because it’s so easy to create plug-ins, I’ve ended up creating quite a few myself both for my own and shared use. The simple plug-in model is a genius concept: It allows for jQuery to stay small with only a core set of features while still exposing all of the functionality that the core library has to any extensions. It’s a model more API vendors should embrace and execute as nicely as jQuery has. What's Not to Like? If all of this sounds like a glowing commercial for a tool, you can be assured that I’m just a happy user who’s stumbled onto this library some time ago and fell in love with it the first time I used it. I tend to be very critical of the tools I use, but I have yet to have any serious complaints about jQuery. This library just works for me and it works the way I like to work. The library is not “the perfect tool” and doesn’t solve every JavaScript and DOM problem for you; however, in my time of over a year with jQuery I haven’t run into a showstopper problem. You may still need a set of a few helper functions to help with non-DOM related functionality. For example, I still use my old JavaScript library for a number of UI and JavaScript utility functionality like date and number formatting, providing windowing support, and a host of other features. This is unlikely to ever go away. But I can simply toss out large parts of my old library because jQuery replaces functionality-in most cases much more elegantly than my own code did. To be honest I’m grasping to find fault with jQuery for balance here because my editor mentioned I should mention the downsides. Sorry-you’ll have to dig up your own dirt. Good luck with that. A quick search around the Web seems to confirm my feelings-there’s not a lot of negative content that digs up dirt on jQuery. But you can judge for yourself by trying it out. My bet is you’ll dig it because it’s quick to pick up, highly intuitive to use, and so practical that it will quickly feel criminal to work on JavaScript without it. AJAX and ASP.NET Server Side Next Time In this article I’ve introduced jQuery’s core functionality for DOM manipulation and JavaScript extensions. I’ve focused on the client-side functionality without any thought given to the server side because ultimately this is what jQuery excels at most. One big area I left out is AJAX and server-side integration with ASP.NET and that’ll be the focus of the next installment. I’ll look at jQuery’s AJAX functionality and how you can use ASP.NET as a back end to receive these AJAX calls in a variety of ways from plain Page callbacks, to REST calls, to using WCF. I’ll also look at integration on how to create ASP.NET controls that use jQuery or jQuery plug-ins in combination with server-side components and how to manage jQuery scripts in general in your ASP.NET applications. Until then check out jQuery for yourself and get excited about the possibilities it offers for improving your client-side Web development. You won’t be disappointed. Rick Strahl |