Chapter 21. jQuery Programming

If knowledge can create problems, it is not through ignorance that we can solve them.

Isaac Asimov

Aside from the social implications of it, the modern Web from a technology viewpoint is mostly about running (a lot) more JavaScript code on the client. JavaScript is a very special type of language; it’s probably not the language everybody would choose to use today to power up the client side of the Web. However, it’s the only common language we have, and we have to stick to it to reach the largest audience.

So what if you want (or more likely need) more power on the client?

Be ready to write more JavaScript code. More importantly, be ready to import more JavaScript code written by others. Either of these two ways of using JavaScript is OK, as they are not mutually exclusive options.

I firmly believe that, at least for the time being, you can’t just transform JavaScript into something else that is radically different from what the language is today. However, the Web has repeatedly proven to be a surprisingly dynamic and agile environment; so who really knows what could happen in five years?

Currently, the most effective approach to adding more power to the client is using ad hoc libraries full of Document Object Model (DOM) facilities and adding new features to the existing JavaScript language. Interestingly, a single all-encompassing library seems not to be realistic. The ideal JavaScript library is often obtained by stacking up and composing together bits and pieces of existing libraries in a custom recipe that suits each particular application.

Many attempts have been made over the years to create the perfect JavaScript library. As it often happens, many libraries participate, but only one wins. And in this regard the winner is jQuery. In this chapter, you’ll discover the capabilities of this library and its powerful extensibility model.

Power to the Client

JavaScript is a language tailor-made for the Web and, more specifically, for the browser. I won’t stray too far from the truth by saying that there’s little life for JavaScript outside the realm of a Web browser, even though the demand for out-of-browser JavaScript is growing and might explode in the near future.

Anyway, today JavaScript still lives for the browser and within the browser. This is the starting point to understand what the language is for and where to look for possible (and really useful) extensions. Not surprisingly, our quest will lead straight to jQuery—currently, a natural extension of most Web applications.

Programming within the Browser

The first appearance of JavaScript as a browser-hosted language dates back to late 1995, when the first beta of Netscape Navigator 2 was released. JavaScript was introduced to give authors of Web documents the ability to incorporate some logic and action in HTML pages. Before then, a Web page was essentially a static collection of HTML tags and text. Historically, the first significant enhancement made to the syntax of HTML was the support for tags to include script code.

Original Goals of the Language

JavaScript was not designed to be a classic and cutting-edge programming language—not even by the standards of 15 years ago. The primary goal of its designers was to create a language that resembled a simpler Java that could be used with ease by inexpert page authors.

To some extent, the design of JavaScript was influenced by many languages, but the predominant factor was simplicity. It was named “JavaScript” because the language was essentially meant to be a powerful language like Java, but focused on scripting. No other relationships, beyond the deliberate reference in the name, exist between Java and JavaScript.

As a result, JavaScript is an interpreted and weakly typed language that also supports dynamic binding and objects. JavaScript, however, is not a fully object-oriented language.

Note

Originally developed at Netscape by Brendan Eich, JavaScript was first named LiveScript. The name was changed to JavaScript when Netscape added support for Java technology in its Navigator browser. The script suffix was simply meant to be the script version of an excellent programming language like Java. In no way was the language supposed to be a spinoff of Java.

Later, Microsoft created a similar language for its Internet Explorer browser and named it JScript to avoid trademark issues. In 1997, JavaScript was submitted to the European Computer Manufacturers Association (ECMA) International for standardization. The process culminated a couple of years later in the standardized version of the language named ECMAScript.

The Scripting Engine

Being an interpreted language, JavaScript requires an ad hoc run-time environment to produce visible effects from the source code. The run-time environment is often referred to as the browser’s scripting engine. As such, the JavaScript run-time environment can be slightly different from one browser to the next. The result is that the same JavaScript language feature might provide different performance on different browsers and might be flawed on one browser while working efficiently on another one. This fact makes it generally hard and time-consuming to write good, cross-browser JavaScript code and justifies the love/hate relationship (well, mostly hate) that many developers have developed with the language over the years.

The diagram in Figure 21-1 shows the overall structure of a scripting engine with an interesting extension—the JavaScript background compiler—that some of the latest browsers are implementing.

The browser’s JavaScript engine.

Figure 21-1. The browser’s JavaScript engine.

The scripting engine is a component that is hosted in the browser and receives the source code to process. Armed with language knowledge, the engine can resolve any name in the source code that can be mapped to a syntax element—keywords, variables, local functions, and objects.

In addition, the source code processed within a Web browser is likely populated with specific objects coming from various sources. For example, you can find DOM objects to access the content being displayed in the page as well as browser-specific objects such as XMLHttpRequest, JSON, and window. Furthermore, any libraries you reference from the page are also published to the engine. After the script has been loaded, the browser runs the script through the engine. This action results in the functionality defined by the commands in the code.

As mentioned, although JavaScript is definitely a stable language that hasn’t faced significant changes for a decade now, virtually any broadly used library is packed with forks in code to distinguish the behavior of different browsers and ensure the same overall interface.

One of the first rules—if not the first rule—you should follow to write rich client applications is get yourself a powerful JavaScript library that adds abstraction and features to the JavaScript language and that works in a cross-browser manner.

Flaws and Workarounds

JavaScript has a number of drawbacks, both technical and infrastructural. In spite of all these factors, though, JavaScript works just great for the majority of Web applications. And nothing any better has been invented yet.

All things considered, the limitations of JavaScript can be summarized as two elements: it is an interpreted language, and it is not fully object oriented. The former drawback makes the language significantly slower than a compiled language. The latter makes it harder for developers to write complex code.

The Google Chrome browser (which you can read more about at http://www.google.com/chrome) is the first browser with an open-source JavaScript engine that compiles source code to native machine code before executing it. As a result, Chrome runs JavaScript applications at the speed of a compiled binary, which is significantly better than any bytecode or interpreted code.

An analogous capability is featured by Internet Explorer 9, which compiles the JavaScript code in the background, leveraging the full capabilities of the underlying hardware. Generally, all browsers (including Mozilla-based browsers and Opera) are evolving their JavaScript engines to achieve performance as close as possible to that of native code.

Because JavaScript is so popular and widely used, planning a significant overhaul of the language is just out of question. For years now, libraries built on top of the core language have been providing facilities to work with remote endpoints, parse data into JSON, and produce UI widgets.

As you saw in Chapter 20, JavaScript can be used to write code that follows two radically different programming paradigms: functional programming and object-oriented programming (OOP). JavaScript is neither 100 percent functional nor object-oriented, but it borrows concepts from both qualified functional and object-oriented languages. This inevitably creates some noise regarding the programming techniques you can employ. As a developer, you must be ready to accept compromises that might not be acceptable in a fully qualified functional or object-oriented scenario. To use JavaScript at its best, you probably have to mix functional features with object-oriented (OO) features.

What You Write JavaScript Code For

The client-side code you are called to write is no longer, and not just, plain scripting of the document object model as it was when the language was introduced. Today, you often use JavaScript for some client-side logic and input validation. In particular, you use JavaScript to download data from the server, implement Windows-like effects such as drag-and-drop, resizing, templates, popup and graphic effects, local data caching, and the management of history and events around the page. You want the JavaScript code to be maintainable and unobtrusive.

Any in-browser JavaScript inevitably deals with the DOM. The DOM, therefore, is the primary object model you need to work with. Any other object model you might want to introduce risks being cumbersome and partially unnecessary.

If you have to write your own framework to support some server-side infrastructure, you probably are better off opting for an object-oriented approach. If your goal, instead, is just to add some presentation logic to the page, you don’t need object orientation in JavaScript. A functional approach combined with rich DOM and page manipulation capabilities is the ideal mix these days. The jQuery library is just the most illustrious example of such a library.

The Gist of jQuery

The main reason for the worldwide success of the jQuery library is its unique mix of functional and DOM programming. The library works by selecting DOM elements and applying functions over them, which is just what client Web developers need to do most of the time.

Details of the Library

The library is made of a single .js file you can download from http://jquery.com. Most ASP.NET Visual Studio templates already include a version of the jQuery library, even though the one included in the template might not be the latest. From the site, you can pick both the minified and debug versions. Compressed, they are a bit more than 20 KB in size. Here’s what you need to link the jQuery library (keeping in mind that the path can change on a per-application basis):

<script type="text/javascript" src="/Scripts/jquery-1.4.4.js"></script>

So if jQuery is not the only option, why is it so popular?

In the first place, the library is lightweight and cross-browser capable. Second, it works by selecting DOM elements via a Cascading Style Sheet 3.0 (CSS3)-compliant syntax and applying functions to each of them. Functions are mostly user-defined, but a number of predefined (and commonly used) functions exist. Third, the library is based on an extensible model that enables developers to write and share their own plug-ins, thus contributing to making the library even more successful.

Microsoft offers support 24 hours a day, seven days a week for the jQuery library when used with ASP.NET and contributes developers to the project. Template support recently added to version 1.4.5 of the library has been contributed by Microsoft. Visual Studio recognizes jQuery code via a proper .vsdoc file and provides IntelliSense support. (See Figure 21-2.)

IntelliSense support for jQuery code.

Figure 21-2. IntelliSense support for jQuery code.

For development purposes, you reference the VSDOC file, as shown here:

<script type="text/javascript" src="/Scripts/jquery-1.4.4-vsdoc.js"></script>

You can get the latest VSDOC IntelliSense file from the Microsoft CDN at the following address: http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.4.4-vsdoc.js. Obviously, you might need to change the file name to get a newer version. The naming convention of the jQuery library is jquery-n.n.n.js, where n.n.n stands for the current version number.

The Root Object

The word query in the library’s name says it all—the jQuery library is primarily designed for running (clever) queries over the DOM. The library supplies a powerful interface to select DOM elements that goes far beyond the simple search for an element that matches a given ID. For example, you can easily select all elements that share a given cascading style sheet (CSS) class, have certain attributes, or appear in a given position in the tree. More importantly, you can chain multiple clauses together and prepare complex queries.

The root of the jQuery library is the jQuery function. Here’s the overall structure of the library:

(
    function( window, undefined )
    {
         var jQuery = (function() {...})();
         /* the rest of the library goes here */
    }
) (window);

The jQuery function just shown is then mapped as an extension to the browser’s window object and is aliased with the popular $ function. The function has the following prototype:

function(selector, context)

The selector indicates the query expression to run over the DOM; the context indicates the portion of the DOM from which to run the query. If no context is specified, the jQuery function looks for DOM elements within the entire page DOM.

The jQuery function typically returns a wrapped set, namely a collection of DOM elements. Nicely enough, this wrapped set is still a jQuery object that can be queried using the same syntax, resulting in chained queries.

jQuery and Functional Programming

In jQuery, you find some basic principles of functional programming. In particular, the library is built around a fundamental type of data—the DOM element. And the library’s root object is essentially a wrapper around DOM elements. Furthermore, DOM elements can be passed into the jQuery object through the type constructor. Finally, the root object can pass its own wrapped values into other functions that return another instance of the same root object.

The net effect is that you build your jQuery code by pipelining function calls to create a super function that just gets some input and returns some output. In the super function, you express behavior by injecting anonymous JavaScript functions as if they were plain values.

Let’s start by playing with the jQuery library.

Working with jQuery

When writing JavaScript intensive applications, you’ll find it quite natural to put a piece of code at the top of each page and set up the DOM to serve the desired logic within the page. Typically, this code initializes global variables and prepares the ground for possible future actions. Ideally, you also want to use this initialization code to arrange event handlers, caching, and downloads of external data.

Because jQuery is designed to query the DOM and work with selected elements, any initialization code should reasonably run only when the DOM is ready. Detecting DOM readiness and writing initialization code with jQuery library is easier than ever.

Detecting DOM Readiness

In the beginning of client-side development, there was just one place where you could put the initialization code of a Web page—in the onload event on either the window object or the <body> tag. The onload event fires as soon as the page has finished loading—that is, once the download of all linked images, CSS styles, and scripts has terminated. There’s no guarantee, however, that at this time the DOM has been fully initialized and is ready to accept instructions.

The DOM ReadyState Property

The document root object in the DOM exposes a read-only readyState property just to let you know the current state of the DOM and figure out when it is OK for your page to start scripting it. Any change to the property is signaled with a readyStateChange event. Web pages are notified of DOM readiness by registering a handler for this event and checking the value of the readyState property in the code.

Most browsers also support the DOMContentLoaded event, which just signals when the DOM is ready. Internet Explorer, however, doesn’t support it.

Using the readyState property is an approach that definitely works, but it is a bit cumbersome. For this reason, most JavaScript frameworks offer their own “ready” event that signals when you can start making calls into the framework safely. In this way, they shield you from the details of the DOM implementation and just let you know when you can do your own thing.

The jQuery library is no exception.

The jQuery’s Ready Function

In jQuery, you select the current DOM document and call the ready function on it. The ready function encapsulates the code to check the value of the readyState property on the DOM’s document object. The ready function takes an anonymous function as a parameter. The argument function is where you specify any initialization code required for the document. Here’s how you use it:

<script type="text/javascript">
$(document).ready(
   function() {
     alert("I'm ready!");
   });
</script>

The jQuery’s ready function provides a cross-browser solution to detect the DOM readiness.

Note that the ready function works only if it’s invoked on the current document. You can’t call the ready function on, say, an image, a script, or a portion of the DOM. In light of this, you can even omit the document selector and resort to the equally acceptable syntax shown here:

<script type="text/javascript">
$(function() {
     alert("I'm ready!");
   });
</script>

The two syntaxes are equivalent. Another approach consists of using the bind method to bind a handler to the ready event of the document:

$(document).bind("ready", function() { ... });

In this case, though, the handler won’t run if at the time of event binding the ready event has already fired. Finally, the ready handler is delayed until the document is ready or runs immediately if the document is already entirely loaded. I’ll return to bind and other event functions later in the chapter.

Onload vs. Ready

Which code runs first, the window’s onload event handler or the call’s jQuery ready function?

The onload event is called after the HTML and any auxiliary resources are loaded. The ready function is called after the DOM is initialized. The two events can run in any order. The onload event won’t ensure the page DOM is loaded; the ready function won’t ensure all resources, such as images, have been loaded.

Another noticeable difference between onload and ready is that you can have multiple calls to ready in a page. You can have only one global onload event handler either defined on the window object or expressed as an attribute on the body tag. When multiple calls to ready are specified, jQuery pushes specified functions to an internal stack and serves them sequentially after the DOM is effectively ready.

It is generally recommended that you use either the ready function or the onload handler. If you need both things, you should use the jQuery’s load function attached to the window object or to more specific elements such as images, scripts, or style sheets:

$(window).load(function() {
    // Initialization code here
});

You typically use load when you need to access specific information on specific page elements such as images or scripts. So in summary, you rarely end up using load on the window object.

Wrapped Sets

Why does the word “query” appear in the name of the library? The ultimate purpose of the jQuery library (j stands for JavaScript) is simplifying the task of getting a selected subset of DOM elements to work with. Put another way, the jQuery library is mostly intended to run queries over the page DOM and execute operations over the returned items.

The query engine behind the library goes far beyond the simple search capabilities of, say, document.getElementById (and related functions) that you find natively in the DOM. The query capabilities of jQuery use the powerful CSS syntax, which gives you a surprising level of expressivity. You find similar query expressivity only in the DOM of HTML 5 when it’s fully defined and widely and uniformly supported.

The query engine of jQuery allows you to select elements that have a given combination of attribute values, appear in a fixed relative position in the DOM tree, or have a particular relationship with other elements. More importantly, you can add filter conditions, chain multiple queries together, and apply them sequentially.

The result of a query is a wrapped set. A wrapped set is an object containing a collection of DOM elements. Elements are added to the collection in the order in which they appear in the original document.

A wrapped set is never null, even if no matching elements have been found. You check the actual size of the wrapped set by looking at the length property of the jQuery object, as shown here:

// Queries for all IMG tags in the page
var wrappedSet = new jQuery("img");
var length = wrappedSet.length;
if (length == 0)
    alert("No IMG tags found.");

Note that the expression just shown, through which you get the wrapped set, is fully equivalent to the more commonly used $(“img”).

The wrapped set is not a special data container; rather, it’s a jQuery-specific term to indicate the results of a query. However, once you hold all the elements you were looking for, you need to process them. To start off, let’s see how to enumerate the content.

Enumerating the Content

To loop through the elements in the wrapped set, you use the each function. The each function gets a function as a parameter and invokes that on each element:

// Prints out names of all images
$("img").each(function(index) {
   alert(this.src);
});

The callback function you pass to each receives the 0-based index of the current iteration. Nicely enough, you don’t need to retrieve the corresponding DOM element yourself; you just use the keyword this to refer to the element currently being processed. If the callback function returns false, the iteration is stopped. Note that each is a quite generic function made available for any task for which a more specific jQuery function doesn’t exist. If you find a jQuery function that already does what you intend to code through each, by all means use the native function.

You use the length property to read the size of the wrapped set. You can also use the size function, but the length property is slightly faster:

// You better use property length
alert($("img").size());

The get function extracts the wrapped set from the jQuery object and returns it as a JavaScript array of DOM elements. If you pass an index argument, instead, it will return the DOM element found at the specified 0-based position in the wrapped set. Note that the get function breaks the jQuery chainability because it returns a DOM object or an array of DOM objects. You can’t further apply jQuery functions to the results of a get call.

Many more operations are available on wrapped sets, and many others can be added through plug-ins. I’ll return to the topic of operations that are possible on a wrapped set later in the chapter, right after discussing the syntax used to arrange queries.

Basic Selectors

A query is characterized by a selector. A selector is simply the expression that, when properly evaluated, selects one or more DOM elements. In jQuery, you have three basic types of selectors—based on ID, CSS, or tag name. In addition, a selector can result from the composition of multiple simpler selectors combined using ad hoc operators. In this case, you have a compound selector.

An ID selector picks up DOM elements by ID. An ID selector commonly selects only one element unless multiple elements in the page share the same ID—this condition violates the HTML DOM standard, but it is not too unusual in the real world. Here’s the syntax of an ID selector:

// Select all elements in the context whose ID is Button1
$("#Button1")

The leading # symbol just tells jQuery how to interpret the following text.

A CSS-based selector picks up all elements that share the given CSS class. The syntax is shown here:

// Select all elements in the context styled with the specified CSS class
$(".header")

In this case, the leading dot (.) symbol tells jQuery to interpret the following text as a CSS style name.

Finally, a tag-based selector picks up all elements with the specified tag, such as all IMG tags, all DIV tags, or whatever else you specify. In this case, the selector consists of the plain tag name—no leading symbol is required:

// Select all IMG elements in the context
$("img")

As mentioned, you can also concatenate two or more selectors to form a more specific one.

Compound Selectors

Concatenation is possible through a number of operators. For example, the white space picks up all elements that satisfy the second selector and are descendants of those matching the first. Here’s an example:

// Select all anchors contained within a DIV
$("div a")

The selector just shown is functionally equivalent to the following jQuery expression:

$("div").find("a");

Similar to the white space, the > operator selects elements that are direct child elements (and not just descendants) of the elements matched by the first selector:

// All anchors direct child elements of a DIV
$("div > a")

The preceding selector is functionally equivalent to the following jQuery expression:

$("div").children("a")

Plain concatenation of selectors results in a logical AND of conditions. For example, consider the following query:

$("div.header.highlight")

It selects all DIV elements styled using both the class header and class highlight.

The + operator—the adjacent operator—selects sibling elements in the second selector immediately preceded by elements selected by the first selector. Here’s an example:

// All P immediately preceded by A
$("a + p")

The ~ operator—the next operator—is similar to + except that it selects sibling elements just preceded by others. Here’s an example:

// All P preceded by A
$("a ~ p")

By using the comma, instead, you return the union of elements queried by multiple selectors. In terms of operations, the comma represents a logical OR of selectors. The next example, in fact, picks up elements that are either A or P:

// All A and all P
$("a, p")

Beyond simple operators, you have filters. A filter is a jQuery-specific expression that contains some custom logic to further restrict the selected elements.

Predefined Filters

Selectors can be further refined by applying filters on position, content, attributes, and visibility. A filter is a sort of built-in function applied to the wrapped set returned by a basic selector. Table 21-1 lists positional filters in jQuery.

Table 21-1. Positional Filters

Filter

Description

:first

Returns the first DOM element that matches

:last

Returns the last DOM element that matches

:not(selector)

Returns all DOM elements that do not match the specified selector

:even

Returns all DOM elements that occupy an even position in a 0-based indexing

:odd

Returns all DOM elements that occupy an odd position in a 0-based indexing

:eq(index)

Returns the DOM element in the wrapped set that occupies the specified 0-based position

:gt(index)

Returns all DOM elements that occupy a position in a 0-based indexing greater than the specified index

:lt(index)

Returns all DOM elements that occupy a position in a 0-based indexing less than the specified index

:header()

Returns all DOM elements that are headers, such as H1, H2, and the like

:animated()

Returns all DOM elements that are currently being animated via some functions in the jQuery library

Table 21-2 lists all filters through which you can select elements that are child elements of a parent element.

Table 21-2. Child Filters

Filter

Description

:nth-child(expression)

Returns all child elements of any parent that match the given expression. The expression can be an index or a math sequence (for example, 3n+1), including standard sequences such as odd and even.

:first:child

Returns all elements that are the first child of their parent.

:last-child

Returns all elements that are the last child of their parent.

:only-child

Returns all elements that are the only child of their parent.

A particularly powerful filter is nth-child. It supports a number of input expressions, as shown here:

:nth-child(index)
:nth-child(even)
:nth-child(odd)
:nth-child(expression)

The first format selects the n.th child of all HTML elements in the source selector. All child elements placed at any odd or even position in a 0-based indexing are returned if you specify the odd or even filter instead.

Finally, you can pass the nth-child filter a mathematical sequence expression, such as 3n to indicate all elements in a position that are a multiple of 3. The following selector picks up all rows in a table (labeled Table1) that are at the positions determined by the sequence 3n+1—that is, 1, 4, 7, and so forth:

#Table1 tr:nth-child(3n+1)

Table 21-3 lists expressions used to filter elements by content.

Table 21-3. Content Filters

Filter

Description

:contains(text)

Returns all elements that contain the specified text

:empty

Returns all elements with no children

:has(selector)

Returns all elements that contain at least one element that matches the given selector

:parent

Returns all elements that have at least one child

As far as content filters are concerned, you should note that any text in an HTML element is considered a child node. So elements selected by the empty filter have no child nodes and no text as well. An example is the <br /> tag.

A popular and powerful category of filters are attribute filters. Attribute filters allow you to select HTML elements where a given attribute is in a given relationship with a value. Table 21-4 lists all attribute filters supported in jQuery.

Table 21-4. Attribute Filters

Filter

Description

 

[attribute]

Returns all elements that have the specified attribute. This filter selects the element regardless of the attribute’s value.

 

[attribute = value]

Returns all elements where the specified attribute (if present) is set to the specified value.

 

[attribute != value]

Returns all elements whose specified attribute (if present) has a value different from the given one.

 

[attribute ^= value]

Returns all elements whose specified attribute (if present) has content that starts with the given value.

 

[attribute $= value]

Returns all elements whose specified attribute (if present) has content that ends with the given value.

 

[attribute *= value]

Returns all elements whose specified attribute (if present) has content that contains the given value.

 

Attribute filters can also be concatenated by simply placing two or more of them side by side, as in the following example:

var elems = $("td[align=right][valign=top]");

The returned set includes all <td> elements where the horizontal alignment is right and the vertical alignment is top.

The next expression, which is much more sophisticated, demonstrates the power and flexibility of jQuery selectors, as it combines quite a few of them:

#Table1 tr:nth-child(3n+1):has(td[align=right]) td:odd

It reads as follows:

Within the body of element Table1, select all <tr> elements at positions 1, 4, 7, and so forth. Next, you keep only table rows where a <td> element exists with the attribute align equal to the value of right. Furthermore, of the remaining rows, you take only the cells on columns with an odd index.

The result is a wrapped set made of <td> elements.

Finally, a couple more filters exist that are related to the visibility of elements. The :visible filter returns all elements that are currently visible. The :hidden filter returns all elements that are currently hidden from view. The wrapped set also includes all input elements of type hidden.

Form Filters

A special family of filters exists for HTML input elements. Table 21-5 lists all of them.

Table 21-5. Input Field Filters

Filter

Description

:input

Returns all elements that have a role in collecting input data

:text

Returns all input elements whose type attribute is text

:password

Returns all input elements whose type attribute is password

:checkbox

Returns all input elements whose type attribute is checkbox

:radio

Returns all input elements whose type attribute is radio

:submit

Returns all input elements whose type attribute is submit

:reset

Returns all input elements whose type attribute is reset

:image

Returns all input elements whose type attribute is image

:button

Returns all input elements whose type attribute is button

:file

Returns all input elements whose type attribute is file

:hidden

Returns all input elements whose type attribute is hidden

:enabled

Returns all input elements that are currently enabled

:disabled

Returns all input elements that are currently disabled

:checked

Returns all input elements that are currently checked

:selected

Returns all input elements that are currently selected

The :input filter, in particular, refers to all logical input elements you might find within a page form and is not limited solely to the <input> elements. In fact, it also picks up <textarea> and <select> elements used to display multiline text boxes and lists. The filters in Table 21-5 provide handy shortcuts for selecting homogeneous elements and are functionally equivalent to the other legal jQuery selectors. For example, :checkbox is equivalent to the following:

form input[type=checkbox]

As you can see in Table 21-5, other nice helpers are available to grab all input elements in a page form that are currently enabled or disabled and all check boxes and radio buttons currently selected.

Filter vs. Find

To further restrict a query, you can use either the find or filter function on a wrapped set. They are not the same, of course. The function filter explores the current wrapped set for matching elements and doesn’t ever look into DOM for descendants. The function find, instead, looks inside of each of the elements in the wrapped set for elements that match the expression. In doing so, however, the function explores the DOM of each element in the wrapped set.

Operating on a Wrapped Set

The power of jQuery descends primarily from the powerful query language that allows you to select nearly any possible combination of DOM elements you can think of. However, the query language would not be much without a rich collection of predefined operations to apply to selected elements. The jQuery library offers a wide range of functions you can apply to the content of a wrapped set. We have already taken a look at how to enumerate the content of a wrapped set; let’s now proceed with more specific operations.

As mentioned, function calls can be chained because any wrapped set returned by a query is in turn another jQuery object that can be further queried. The following expression is just fine:

$(selector).hide().addClass("hiddenElement");

It first hides from view all matching elements and then adds a specific CSS class to each of them. In jQuery, however, not all functions return a jQuery object. You must be aware of this to avoid nasty script errors. Chaining functions that act as value getters (not returning a jQuery object) is fine as long as these functions go at the end of the expression.

Important

Before going any further, it is worth recalling that this is an ASP.NET Web Forms book. This means that in spite of the changes introduced in version 4 to the algorithm for generating control IDs, there is still a chance you’ll end up using complex hierarchies of controls in which you don’t exactly know the actual ID being generated for a given segment of the markup. As you saw in Chapter 6, this problem is addressed by the ClientIDMode property added in ASP.NET 4 to the Control class. An easy way to retrieve the client ID of an ASP.NET control—at least when the ASP.NET control outputs a single piece of HTML—is the following:

<script type="text/javascript">
   var selector = "#<%= PanelAdvancedOptions.ClientID %>";
   ...
</script>

The code block captures the value of the ClientID property of the specified ASP.NET control and will emit it into the script block.

Controlling Visibility

The functions hide and show allow you to remove from view or display all elements that match a given selector. These functions help a lot in building dynamic views where you need to adjust the next user interface based on a current user’s choice. Here’s how to hide an element:

<script type="text/javascript">
    $(document).ready(function () {
        $("#panelAdvancedOptions").hide();
    });
</script>

To display it, you just replace the call to hide with a call to show. The most interesting aspect of show and hide methods is the built-in support for completion callbacks and effects. Here are the full signatures supported by the functions:

$(selector).hide()
$(selector).show()
$(selector).hide(duration, callback)
$(selector).show(duration, callback)
$(selector).hide(duration, easing, callback)
$(selector).show(duration, easing, callback)

When duration is specified, functions perform an animation while hiding or showing the element. The duration argument indicates the time (in milliseconds) the animation will take to run. You can also specify a couple of descriptive values such as fast and slow, which correspond to fixed values—specifically, 200 and 600 milliseconds.

The easing parameter indicates the internal function to use to perform the animation. Default values are linear and swing, which animate height, width, and opacity. Different effects can be achieved only through plug-ins.

The callback function runs at the end of the animation. The function doesn’t get any parameter. However, the expression this in the context of the callback refers to the element being animated.

$("#panelAdvancedOptions").show(1000, function () {
  // Perform some action necessary when the panel is displayed.
  // The panel takes 1 second of animation to display.
  ...
});

Invoking show and hide methods without parameters is nearly equivalent to setting the display CSS attribute. The only difference is that the assigned value is cached for the purpose of toggling it through the toggle function:

$("#panelAdvancedOptions").toggle();

The preceding call toggles the visibility state of all elements in the wrapped set, making visible hidden elements and hiding visible elements.

In addition to plain show and hide methods, you also have methods to apply visibility changes through specific animations, such as sliding and fading. Methods are listed in Table 21-6.

Table 21-6. Visibility Effects

Function

Description

slideDown

Displays any matching elements by increasing their height progressively

slideUp

Hides any matching elements by decreasing their height progressively

slideToggle

Shows or hides all matching elements inverting the current sliding setting

fadeIn

Fades in any matching elements by reducing their opacity progressively

fadeOut

Fades out any matching elements by increasing their opacity progressively

fadeTo

Fades the opacity of all matching elements to a specified opacity

Styling

Applying CSS classes to selected elements is easy too. If you’re interested in tweaking just individual CSS properties, you can use the css function, as shown here:

$("form input").css(
   {'color' : 'blue',
    'background-color' : 'yellow',
    'border-style' : 'dashed'}
);

To work with entire CSS classes, you have ad hoc functions such as those in Table 21-7.

Table 21-7. Working with CSS Classes

Function

Description

addClass

Adds the specified CSS class to any matching elements

removeClass

Removes the specified CSS class from any matching elements

toggleClass

Toggles the specified CSS class from any matching elements, meaning that the elements will be added to the class if they’re not already assigned and removed from the class if they are currently assigned

Binding and Unbinding Events

For years, it has been common to write HTML pages with client buttons explicitly attached to JavaScript event handlers. Here’s a typical example:

<input type="button" value="Click me" onclick="fnClick()" />

From a purely functional perspective, there’s nothing wrong with this code—it just works as expected and runs the fnClick JavaScript function whenever the user clicks the button. This approach, however, is largely acceptable when JavaScript is just used to spice up Web pages; it becomes unwieldy when the amount of JavaScript code represents a significant portion of the page.

The expression “unobtrusive JavaScript” is popular these days, and it just means that it would be desirable not to have explicit links between HTML elements and JavaScript code. In a way, unobtrusive JavaScript is the script counterpart of CSS classes. With CSS, you write plain HTML without inline style information and designer style elements using classes. Likewise, you avoid using event handler attributes (onclick, onchange, onblur, and the like) and use a single JavaScript function to attach handlers, upon page loading, wherever required.

The jQuery library provides a bunch of functions to bind and unbind handlers to events fired by DOM elements. The pair of bind and unbind functions are used to attach a callback function to the specified event:

// All elements that match the selector will be attached
// the same handler for the click event.
$(selector).bind("click", function() {
   ...
});

You use the unbind function to detach any currently defined handler for the specified event:

$(selector).unbind("click");

The unbind function doesn’t remove handlers that have been inserted directly in the markup through any of the onXXX attributes.

The jQuery library also defines a number of direct functions to bind specific events. Facilities exist for events such as click, change, blur, focus, dblclick, keyup, and so forth. The following code shows how to bind a handler for the click event:

$(selector).click(function() {
   ...
});

Invoked without a callback, the same event functions produce the effect of invoking the current handler, if any are registered. The following code, for example, simulates the user’s clicking on a specific button:

$("#Button1").click();

You can achieve the same effect in a more generic way using the trigger function:

$("#Button1").trigger("click");

Event handlers receive a jQuery internal object—the Event object. This object provides a unified programming interface for events that goes hand in hand with the World Wide Web Consortium (W3C) recommendation, and it resolves discrepancies in the slightly different implementations provided by some browsers:

$("#Button1").click(function(evt) {
    // Access information about the event
    :

    // Return false if you intend to stop propagation
    return false;
});

The Event object features properties such as mouse coordinates, the JavaScript time of the event, which mouse button was used, and the target element of the event.

Note

In JavaScript, the time is expressed as the number of milliseconds elapsed from a fixed date—January 1, 1970.

Live Event Binding

Live binding is a nice feature of jQuery that allows you to keep track of event bindings for a given subset of DOM elements for the entire page lifetime. In other words, if you opt for live binding instead of plain binding, you are guaranteed that any new dynamically added elements that match the selector will automatically have the same handlers attached. You operate live binding through live and die functions. Here’s an example:

$(".specialButton").live("click", function() {
   ...
})

All buttons decorated with the specialButton CSS style are attached the given function as the handler for the click event. The difference between using live and bind (or specific event functions such as click) is that when live is used, any new DOM elements added to the page and decorated with the specialButton style automatically have the handler added. This won’t happen if bind is used. To stop live binding for some elements, you need to use the die function:

$(".specialButton").die("click");

Manipulating the DOM

The standard DOM provides a rich set of methods to create HTML trees dynamically. It turns out, however, that in nearly all browsers the performance of native DOM objects is poor compared to using the innerHTML property, which is not officially part of the DOM standard. While functions and objects to neatly compose a piece of HTML are great things to have, the ability to select a plain chunk of HTML and get the resulting DOM tree is even more compelling. In jQuery, you find an API that supports both approaches.

Creating a DOM Tree

The simplest way to create a new DOM tree in jQuery consists of passing an HTML string to the jQuery (or $) function, as shown here:

// Represents a DOM tree with a UL list and two child LI elements
$("<ul><li>One</li><li>Two</li>");

You can also indicate style information, event handlers, and set attributes. The following example returns a DIV element with some inner text, a CSS class, and a click handler:

$("<div />", {
                class: "panel",
                text: "Click me!",
                click: function() {
                   $(this).toggleClass("extra");
                }
              }
);

The DOM you created in this way is not part of the page yet. To add it to the existing page DOM, an additional step is required.

Adding Elements to the DOM

The jQuery library defines a bunch of functions to insert the DOM tree resulting from a piece of HTML somewhere in the existing DOM. The following code shows how to insert a dynamically created image after each element in the wrapped set. The wrapped set includes all LI child elements of a UL element identified by name:

$("#ShoppingList li").after("<img src='tick.jpg' />");

The function after inserts the DOM tree (specified via plain HTML text) after any matching element in the set. Other available functions are before, prepend, and append. The function prepend puts the DOM before the inner text of matching elements, whereas the function append puts the DOM right after the inner text of matching elements.

You can also add elements to an existing DOM the other way around—that is, by first creating the new DOM and then inserting it in some way around elements in a wrapped set. You use insertAfter and insertBefore to insert a DOM after or before an existing element:

$(html).insertAfter(selector);
$(html).insertBefore(selector);

You use the prependTo and appendTo functions to insert something before and after, respectively, the inner text of a matching element:

$(html).prependTo(selector);
$(html).appendTo(selector);

To detach an existing DOM subtree, you use the method detach. A detached DOM tree is treated like a dynamically created DOM tree and can be moved around the DOM. Imagine the following page content:

<div id="section">
    <h1>Title</h1>
    <hr id="Separator" />
    <p>Content</p>
</div>

Consider now the following script code:

<script type="text/javascript">
    var naturalOrder = true;
    function swapText() {
        var title = $("h1", "#section").detach();
        var content = $("p", "#section").detach();

        if (naturalOrder) {
            title.insertAfter("#Separator");
            content.insertBefore("#Separator");
        }
        else {
            content.insertAfter("#Separator");
            title.insertBefore("#Separator");
        }
        naturalOrder = !naturalOrder;
    }
</script>

The swapText function is defined as the click handler of a button in the page. When clicked, it first grabs a reference to the DOM subtrees for the title and content. Note that the #section parameter identifies the context for the selector—it gets all h1 elements within the specified section of the page. Next, the position of the title and content is toggled around the hr as you click the button. (See Figure 21-3.)

Toggling DOM subtrees in a page.

Figure 21-3. Toggling DOM subtrees in a page.

Important

In general, it is preferable to create a DOM tree using plain HTML when the HTML block you need is fairly complex. You might want to use insertion methods only for single elements (including an entire DOM subtree), In other words, it is not recommended that, say, to create a UL list you place multiple calls to insert the UL tag and then each of the required LI tags. You compose the HTML string and get it as a DOM in a single step.

Removing DOM Elements

To remove elements from the DOM, you have various options. You can remove all elements that match a given selector using the following code:

$(selector).remove();

The empty function, on the other hand, just empties the body of each element that is selected through the query expression:

$(selector).empty();

Finally, the aforementioned detach function detaches a DOM subtree from the main DOM but keeps it referenced in memory so that you can re-add it everywhere at any time:

$(selector).detach();

Modifying DOM Elements

HTML DOM elements are characterized by attributes, inner text, and HTML. For each of these, you have ad hoc functions. For example, you use the attr function to read and write the content of a given attribute. The following code reads the value of the maxlength attribute of a given text box:

var maxLength = $("#TextBox1").attr("maxlength");

To set it, instead, you just add a second parameter to attr, as shown here:

$("#TextBox1").attr("maxlength", 10);

You can use the function attr to read and write any attributes. For the value attribute, however, you can resort to the more specific val function. The val function has the same usage as the attr function.

To get and set the inner text of an element, you use the text function. The html function is used to get and set the inner HTML of an element.

Sometimes you just want to make a copy of an element DOM element or subtree and duplicate it in various places around the page. The jQuery library offers the clone function:

$(selector).clone();

Used in this way, the function performs a deep copy of matching elements, including attributes and descendants. The function, however, also supports an optional Boolean argument:

$(selector).clone(true);

If set to true (false is the default), the function performs a deep copy of matching elements, including attributes and descendants plus event handlers.

The jQuery Cache

In client Web applications, data storage is an area of growing importance, and the work behind done on it around the HTML 5 specification confirms this fact. Some browsers currently support forms of local storage even though the API is not unified yet. Local storage is persistent and is meant to replace certain use of cookies in the long run—for example, to store user-specific data. An in-memory cache is a different kind of thing, but it still has its own space.

Cached Data and DOM Elements

The jQuery library offers a simple but quite effective API to store data in the browser’s memory for the duration of the session. Any data you park in the jQuery cache is lost once you close the browser window. The jQuery cache is centered on the data function. This method allows you to associate some arbitrary data with all elements that match the selector.

Note that most of the time, though, you’ll use selectors that match just a single DOM element. If multiple elements are selected, no data duplication will ever occur—only the reference is duplicated, not the data.

The jQuery cache is implemented as a plain dictionary where each element is characterized by a name and a value. What about naming conventions to ensure uniqueness of entries? Binding data to DOM elements, in full respect of the jQuery philosophy, is also helpful because it makes it significantly simpler to name elements. Cached entries can have the same name as long as they are bound to different DOM elements.

Working with Data in the In-Memory Cache

To add data to the cache, you select the DOM elements and then invoke the data function, passing the key and value.

$("#Grid1").data("DataSource", value)

The cache is fairly useful for storing data you download once and reuse frequently within the page. When you have a master/detail view and you get data for the detail view via Ajax, a call to the data function can save you roundtrips within the same session. Have a look at Figure 21-4.

An Ajax page that retrieves customer details from the server.

Figure 21-4. An Ajax page that retrieves customer details from the server.

Every time the user selects a letter, the page downloads the list of all customers whose name begins with the letter. If the user clicks twice on, say, “A,” the list of customers is downloaded only once. Here’s the script code that manages the clicking:

// Attempt to grab data from the cache first
var data = loadFromCache(selection);
if (typeof (data) !== 'undefined') {
    fillViewInternal(data, true);
    return;
}

// Grab data from the server asynchronously
loadFromSource(selection);

Inside of the loadFromCache function, you simply build the key and place a call to the data function:

function loadFromCache(query) {
    var key = "Customers_" + query;
    var cachedInfo = $("#RootView").data(key);
    return cachedInfo;
}

Inside of the loadFromSource function, instead, you store downloaded data right into the cache object:

var key = "Customers_" + query;
$("#RootView").data(key, downloadedInfo);

Once it’s placed in the cache, the data never expires and must be removed manually to free up memory. To remove a piece of data from the cache, you use the removeData method:

$("#RootView").removeData(key);

Ajax Capabilities

Ajax support in jQuery is centered on an abstraction of the browser’s XMLHttpRequest object and counts on a bunch of helper functions that address specific scenarios, such as getting a JSON response, getting a script file, or performing a cross-domain call.

Plain Ajax Caller

In jQuery, to compose and control all aspects of your Web request, you use the ajax function, as shown next:

$.ajax(
  {
    type: "POST",
    url: "getOrder.aspx",
    data: "id=1234&year=2010",
    success: function(response) {
      alert( response );
    }
  }
);

The ajax function gets a list of parameters, such as type, url, data, dataType, cache, async, and success. The dataType parameter indicates the type of the expected response (for example, HTML, XML, JSON, JSONP, script). A few other parameters exist to let you further configure the HTTP request. You can refer to the jQuery online documentation for further details. The URL is http://api.jquery.com/jQuery.ajax.

The async parameter indicates whether the call has to go asynchronously or not. The cache Boolean parameter indicates whether you want the library to cache the response for future access to the same URL. Ajax calls are always cached by default except for when the data type is JSONP or script.

The $.ajax function supports several callbacks. The beforeSend callback is invoked just before sending the request out. The callback receives the settings of the call and represents your last chance to modify the call. The complete callback is invoked as soon as the response is received and regardless of the outcome. The callback receives a description of the HTTP status of the request and indicates whether the request completed successfully, resulted in an error, timed out, or pointed to a resource that was not modified. The callback won’t receive the actual response, if there is any. Past the complete callback, the library fires either the success or error callback, depending on the context. The success callback receives the response sent over the wire by the server. The error callback gets a code for the type of error (timeout, parse, or error) and an exception object that provides, if possible, more details about the failure.

On top of the ajax function, a number of shortcut functions have been created that make it simpler for developers to place certain specific types of calls, such as calls for getting a script file or a JSON string. The get and post functions also exist to perform plain HTTP GET and POST requests.

Global Ajax Event Handlers

The jQuery library provides a bunch of global handlers for Ajax events so that you can register your handlers that are invoked for each Ajax operation regardless of the code that triggers it. You can add handlers for the events in Table 21-8.

Table 21-8. Global Ajax Events

Event

Description

ajaxComplete

Fires upon completion of any Ajax request, regardless of the outcome

ajaxError

Fires when an Ajax call fails

ajaxSend

Fires when an Ajax request is sent

ajaxStart

Fires when an Ajax request begins being processed

ajaxStop

Fires when no pending Ajax requests are left

ajaxSuccess

Fires when an Ajax request completes with success

You can have multiple handlers for each of these events. If multiple handlers are registered, all of them are invoked in order.

Getting Scripts

The getScript function requires you to provide the URL for the script file and an optional callback to execute upon downloading the script. Here’s the signature of the function:

$.getScript(url, succeededCallback)

The interesting thing about the function is that the downloaded script is processed by jQuery right after download. This means that in the callback, you can already start using objects and features available in the script:

<script type="text/javascript">
  $.getScript("mylib.js", function() {
     // Start using the features of the downloaded script here
     ...
  });
</script>

The request being placed for the script is an HTTP GET. Keep in mind that if you need to tweak the request beyond the hardcoded settings of the getScript function, you better resort to the ajax function.

Getting JSON

The getJSON function is ideal for invoking an HTTP endpoint that is expected to return a JSON-encoded string. Here’s the signature of the function:

$.getJSON(url, inputData, succeededCallback)

When you make a JSON request, you might need to send some data over to the remote server to guide the generation of the response. The second argument to getJSON represents the input you intend to pass. Here’s an example:

var playerId = 1;
$.getJSON("/yourServer/Player/Details", playerId, function(jsonData) {
    // Start using the information stored in the downloaded object here
    displayDetailsForPlayer(jsonData);
});

The getJSON function appends any input data to the URL as a query string. If the data is not of a primitive type, the function will convert it to a string before appending it to the URL. The request is placed as an HTTP GET request.

Any response is assumed to be JSON and is parsed as such using the global $.parseJSON function. The callback receives the parsed data ready to use.

Getting HTML

A frequent action you might want to perform from a client page is downloading some HTML via a simple GET request. The load function is an instance (as opposed to global) function that you can call over a wrapped set. Here’s the signature of the function:

$(selector).load(url, inputData, succeededCallback)

Note that input data and callback function are optional. In particular, the method is automatically bound to a default callback function that appends the downloaded markup to all elements in the wrapped set. Here’s an example:

var templateType = 1;
$("#panelAdvancedOptions").load("/template.aspx", templateType);

If any callback is provided in the call, it is executed after the default callback. No call is ever attempted if the wrapped set is empty. If the input data is a JavaScript object, the request goes out as a POST instead of a GET.

You are not forced to download the entire content of the provided URL. If the URL contains a white space, anything that follows is interpreted as a jQuery selector. Look at the following example:

$("#panelAdvancedOptions").load("/template.aspx #area_1");

The entire URL content is downloaded, but jQuery then discards everything but the DOM tree selected by the #area_1 expression. When you use load, you should be aware that some tags might be discarded during the parsing process. This typically occurs with tags such as <html> and <title>, which are usually already part of the page.

Cross-Domain Calls

The biggest difference between making a browser-led request and an Ajax-led request is in what happens after the response has been downloaded. The browser safely processes the response to display it. The script, on the other hand, can potentially make any use of the downloaded response—from building hopefully innocuous mashups to preparing cross-site scripting attacks. For this reason, all browsers implement the Same-Origin Policy (SOP), which means that script-led calls are allowed to hit only the same server that served the current page.

Nobody complained about SOP until Ajax became as popular as it is today. SOP represents a serious limitation for developers of Ajax applications because it prevents you from easily creating mashups and, more in general, to requesting data from a site that lives on a different host or that uses a different protocol. Workarounds have been in the works for years, but we’re still looking for an official standard solution to the issue. W3C has a working draft for something called Cross-Origin Resource Sharing (CORS), which defines a common ground for browsers and Web servers to interoperate and enable applications to perform secure cross-site data transfers. Some browsers currently support CORS to some extent and through different APIs. That will probably be the mainstream approach in the near future.

While waiting for that, you might want to consider other approaches, such as using a server-side proxy, Silverlight or Flash applets and their workarounds to bypass SOP, and leveraging cross-domain enabled HTML tags such as <script> and <iframe>.

Note

When it comes to cross-domain calls, these are the options that work without requiring each user to tweak security settings on her browser. SOP is ultimately a browser policy, and each user can disable it by changing the browser’s security settings.

Cross-Domain HTML Tags

Both the <script> and <iframe> tags can be configured to download resources from any site, regardless of any origin policy that might be set. An <iframe> element can successfully download content from just about anywhere, but browsers apply restrictive policies as far as scripting that content is concerned. Cross-frame scripting is not allowed if content comes from different domains. So you’re back at square one: how can you actually consume the downloaded content? In the end, the <iframe> trick proves helpful only when you need to upload data in a fire-and-forget manner to a cross-domain site.

With the <script> tag, instead, the downloaded content is restricted to JavaScript, but it can be freely consumed from within the caller page. With a bit of help from the remote server, you can download usable data from a different domain in the form of a JavaScript string and process it on the client. This requires using the JSON with Padding (JSONP) protocol.

A JSONP solution is effective and cross-browser capable, but it can be used only with agreeable sites and in conformance with the rules they set.

Basics of JSONP

A JSONP-enabled Web site is a Web site exposing a public endpoint that agrees to return a JSON string padded with a call to a caller-defined JavaScript function. For example, suppose that dino.com exposes an endpoint like this one:

http://www.dino.com/public/getcustomer/123

When invoked, the endpoint returns a JSON string that represents an object. If you try to call the URL just shown via Ajax, you likely will get an “access denied” error because of the SOP. If you use the same URL within a <script> tag, however, you successfully download the response of the method, except that you can’t do much to further process it:

<script type="text/javascript"
        src="http://www.dino.com/public/getcustomer/123" />

A JSONP-enabled endpoint would rather wrap the JSON output string in a call to a JavaScript function that is defined locally within the context of the caller server. The JSONP output would look like this:

myHandler("{'Id'='...', 'CompanyName'='...', ...}");

Because all browsers evaluate any content downloaded via a <script> immediately, JSONP does the trick of invoking some cross-domain code and processing the output locally. The myHandler function mentioned here is supposed to be a JavaScript function defined by the same developer who actually places the cross-domain Ajax call.

With JSONP, you find a way to instruct the remote server to return a string that wraps the JSON data into a call to your JavaScript function. A JSONP-enabled site is a site that offers you a programmatic and documented way to indicate which JavaScript function the response has to be wrapped in. Most JSONP sites today allow this through an ad hoc parameter in the query string. For example, Flickr recognizes the jsoncallback parameter.

JSONP in jQuery

Cross-domain calls can be successful only when you call a server that is JSONP enabled. If this condition is true, you can use many of the jQuery Ajax functions to set up a successful cross-domain call. For example, you can use the $.getScript function, append the target JavaScript function name in the query string, and skip over the jQuery callback:

$.getScript("http://someserver/GetCustomer?js=myHandler", function () { })

Your JavaScript function will take care of processing the results of the query in JSON format.

Although this approach is fully functional, it deviates a bit from the standard jQuery programming model in which the callback function defines the behavior to take at the end of the operation. For this reason, the $.getJSON function offers to generate a predefined but randomly named function to bypass browser policies. The predefined behavior of the autogenerated function will just invoke the callback, passing the JSON data. You trigger the generation of the random name using the following notation:

$.getJSON("http://someserver/GetCustomer?js=?", function () {
   // Place your code here that processes the response
   ...
})

The query string parameter (js in the example) has to match the query string parameter that the server recognizes and supports. The ? placeholder instructs jQuery to generate a random and unique name. The following is a sample heading for a JSONP request that goes through jQuery:

GET /GetCustomer?js=jsonp1294078062559 HTTP/1.1

As a developer, you have no control over the algorithm that generates the JavaScript function name. Using a fixed name, however, brings you some benefits in terms of caching ability. If you use the $.ajax function to arrange a JSONP call, you can use the jsonp and jsonpcallback parameters to replace the query string parameter name and the JavaScript function name, respectively.

Important

As mentioned, Microsoft provides full support for jQuery when it’s used within ASP.NET applications. Microsoft also created a few components that were accepted as official jQuery plug-ins in late 2010.

At least the biggest of them—the Templates plug-in—is incorporated in the main library with version 1.5. The Templates plug-in fills a significant gap in client-side programming because it provides a way to declare HTML-based, data-bound templates. Ajax calls make it easy to download fresh JSON data, but displaying raw data is never easy because you just want to display data in the context of a rich graphical layout. With templates, you have the power of HTML for the layout and an ad hoc syntax to control how external data is inserted.

Another interesting plug-in from Microsoft is the Data Link plug-in, which allows you to implement an MVVM-like design on the client. The plug-in keeps your user interface and data synchronized. It also makes it possible to keep the input fields of an HTML form in sync with the properties of a JavaScript object.

Finally, the third Microsoft plug-in is the Globalization plug-in, which emits on the client information about more than 350 different cultures, thus enabling you to use formats or parse numbers, dates and times, calendars, and currencies according to the current settings.

Summary

As emphatic as it might sound, knowing how to use JavaScript is a necessary skill today, whether you use a rich library or not.

jQuery delivers a number of benefits. In the first place, it makes JavaScript code easier and quicker to write. The library provides helper functions that dramatically increase your productivity while decreasing frustration. The key to the wide adoption of jQuery is probably that it makes it simpler to do what developers need to do more often—query for DOM elements and manipulate them.

No ASP.NET application today can ignore client programming and jQuery. Microsoft now fully supports jQuery and has abandoned further development of the Microsoft AJAX Client library. Isn’t this a big enough reason to develop JavaScript skills?

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.198.183