Chapter 9. Prominent, powerful, and practical plugins

This chapter covers

  • An overview of the jQuery plugins
  • The official Form Plugin
  • The official Dimensions Plugin
  • The Live Query Plugin
  • The UI Plugin

In the first eight chapters of this book, we focused on the capabilities that the core jQuery library makes available to us as page authors. But that’s the tip of the iceberg! The immense collection of available jQuery plugins is impressive and gives us even more tools, all based on the jQuery core, to work with.

The creators of the core jQuery library carefully chose the functions needed by the vast majority of page authors and created a framework on which plugins can readily be built. This keeps the core footprint as small as possible and lets us, the page authors, decide how we want to spend the rest of our bandwidth allowance by picking and choosing what additional functionality is important enough to add to our pages.

It’d be an impossible task to try to cover all of the jQuery plugins in the space of a chapter, perhaps even in the space of a single book, so we had to choose which plugins to talk about here. It was a tough call, and the plugins we included are those that we felt were either important enough or useful enough to the majority of web application developers to warrant coverage.

Non-inclusion of a plugin in this chapter is most certainly not an indictment of a plugin’s usefulness or quality! We just had to make some hard decisions.

You can find information on all the available plugins by visiting http://docs.jquery.com/Plugins or http://jquery.com/plugins/most_popular.

We also can’t completely cover the plugins that we will discuss, but this chapter should give you a good basic understanding of the plugins and when they can be applied. Consult the official documentation for each plugin to fill in any gaps in the coverage here.

Let’s start by looking at a plugin that we previously mentioned on a number of occasions.

9.1. The Form Plugin

Dealing with forms can be a hassle. Each control type has its particular quirks, and form submission can often take unintended paths. Core jQuery has a number of methods to help tame forms, but there’s only so much that it can do for us. The purpose of the official Form Plugin is to help fill these gaps and help us take control of form controls.

This plugin can be found at http://jquery.com/plugins/project/form and resides in the file jquery.form.js.

It augments the form functionalities in three areas:

  • Getting the values of form controls
  • Clearing and resetting form controls
  • Submitting forms (including file uploads) via Ajax

Let’s start with getting form control values.

9.1.1. Getting form control values

The Form Plugin gives us two ways to get the values of form controls: as an array of values or as a serialized string. There are three methods that the Form Plugin provides to obtain control values: fieldValue(), formSerialize(), and fieldSerialize().

Let’s look at grabbing field values first.

Getting control values

We can get the values of form controls using the fieldValue() command. At first glance, you might think that fieldValue() and val() are redundant. But prior to jQuery 1.2, the val() command was considerably less capable, and fieldValue() was designed to make up for its deficiencies.

The first major difference is that fieldValue() returns an array of all the values for form controls in its wrapped set, whereas val() only returns the value of the first element (and only if that element is a form control). In fact, fieldValue() always returns an array, even if it only has one value or no values to return.

Another difference is that fieldValue() ignores any non-control elements in the wrapped set. If we create a set containing all elements on a page, an array that contains only as many control values as fieldValue() finds will be returned. But not all controls have values in this returned array: like the val() command, fieldValue(), by default, returns values only for controls that are deemed successful.

So what’s a successful control? It’s not a control that can afford a stable of fancy sports cars, but a formal definition in the HTML Specification[1] that determines whether a control’s value is significant or not and whether it should be submitted as part of the form.

1http://www.w3.org/TR/REC-html40/

We won’t go into exhaustive detail here; but, in a nutshell, successful controls are those that have name attributes, aren’t disabled, and are checked (for checkable controls like check boxes and radio buttons). Some controls, like reset and button controls, are always considered unsuccessful and never participate in a form submission. Others, like <select> controls, must have a selected value to be considered successful.

The fieldValue() command gives us the choice whether to include unsuccessful values or not; its syntax is as follows:


Command syntax: fieldValue

fieldValue(excludeUnsuccessful)

Collects the values of all successful form controls in the wrapped set and returns them as an array of strings. If no values are found, an empty array is returned.

Parameters

excludeUnsuccessful

(Boolean) If true or omitted, specifies that any unsuccessful controls in the wrapped set be ignored.

Returns

A String array of the collected values.


We’ve set up another handy lab page to demonstrate the workings of this command. You’ll find this page in the file chapter9/form/lab.get.values.html; when displayed in your browser, it will appear as shown in figure 9.1.

Figure 9.1. The Get Form Values Laboratory helps us to understand the operation of the fieldValue() and the serialize() commands.

Bring up this page, and leaving the controls in their initial state, click the Get Successful Values button. This causes the following command to be executed:

$('#testForm *').fieldValue()

This creates a wrapped set of all children of the test form, including all the labels and <div> elements, and executes the fieldValue() command on it. Because this command ignores all but form controls and, without a parameter, only includes successful controls, the results displayed on the page are

['some text','Three','cb.2','radio.2','Lorem ipsum dolor sit amet, consectetuer adipiscing elit.']

As expected, the values for the text field, the dropdown, the checked check box, the checked radio button, and the text area are collected into an array.

Now go ahead and click the Get All Values button, which executes the command

$('#testForm *').fieldValue(false)

The false parameter to this command instructs it not to exclude unsuccessful controls, and we can see the more inclusive results as follow:

['some text','Three','One','Two','Three','Four','Five','cb.1', 'cb.2','cb.3','radio.1','radio.2','radio.3','Lorem ipsum dolor sit amet, consectetuer adipiscing elit.','','','','']

Note that not only have the values for the unchecked check boxes and radio buttons been included but also empty strings for the values for the four buttons.

Now, have some fun playing around with the values of the controls and observing the behavior of the two forms of the fieldValue() command until you feel you’ve got it down.

Getting the values of the controls in an array can be useful when we want to process the data in some way; if we want to create a query string from the data, the serialize commands will do that for us. Let’s see how.

Serializing control values

When we want to construct properly formatted and encoded query strings from the values of form controls, we turn to the formSerialize() and fieldSerialize() commands. Both of these wrapper methods collect values from the wrapped set and return a formatted query string with the names and values properly URL-encoded. The formSerialize() method accepts a form in the wrapped set and serializes all of the successful child controls. The fieldSerialize() command serializes all of the controls in the wrapped set and is useful for serializing only a portion of a form.

The syntaxes of these commands are as follow:


Command syntax: formSerialize

formSerialize(semantic)

Creates and returns a properly formatted and encoded query string from the values of all successful controls in the wrapped form.

Parameters

semantic

(Boolean) Specifies that the order of the values in the query string follows the semantic order of the elements—the order in which the elements are declared in the form. This option can be much slower than allowing random order.

Returns

The generated query string.



Command syntax: fieldSerialize

fieldSerialize(excludeUnsuccessful)

Creates and returns a properly formatted and encoded query string from the values of controls in the wrapped form.

Parameters

excludeUnsuccessful

(Boolean) If true or omitted, specifies that any unsuccessful controls in the wrapped set be ignored.

Returns

The generated query string.


The semantic parameter to formSerialize() deserves special note. When specified as true, the serialized values will be in the order that they would be in if the form were submitted through the conventional means, making any submission of these values exactly emulate a browser submission. We should only use this when absolutely necessary (it’s usually not) because there’s a performance penalty to be paid.


Warning

The semantic flag will cause the order of the parameters to be specified in the submitted data in semantic order, but what the server-side code does with this order isn’t under the control of the client-side code. For example, when using servlets, a call to the getParameterMap() method of the request instance won’t preserve the submitted order.


We can use the Get Form Values Laboratory page to observe the behavior of these commands. Load the page, and leaving the controls be, click the Serialize Form button. This will execute a formSerialize() command on the test form as follows:

$('#testForm').formSerialize()

This results in

text=some%20text&dropdown=Three&cb=cb.2&radio=radio.2&textarea=Lorem%20ipsum%20dolor%20sit%20amet%2C%20consectetuer%20adipiscing%20elit.

Notice that all successful form controls have their names and values collected, and the query string created using this data has been URL-encoded.

Clicking the Serialize Fields button executes the command

$('#testForm input').fieldSerialize()

The wrapped set created by this selector includes only a subset of the form’s controls: those of type input. The resulting query string, which includes only the wrapped control elements that are successful, is as follows:

text=some%20text&cb=cb.2&radio=radio.2

One reason that we might want to serialize form controls into a query string is to use as the submission data for an Ajax request. But wait! If we want to submit a form via Ajax rather than through the normal process, we can turn to yet more features of the Form Plugin. But before we get to that, let’s examine a few commands that allow us to manipulate the form controls’ values.

9.1.2. Clearing and resetting form controls

The Form Plugin provides two commands to affect the values of a form’s controls. The clearForm() command clears all fields in a wrapped form, whereas the resetForm() command resets the fields.

“Ummm, what’s the difference?” you ask.

When clearForm() is called to clear form controls, they are affected as follows:

  • Text, password, and text area controls are set to empty values.
  • <select> elements have their selection unset.
  • Check boxes and radio buttons are unchecked.

When resetForm() is called to reset controls, the form’s native reset() method is invoked. This reverts the value of the controls to that specified in the original HTML markup. Controls like text fields revert to the value specified in their value attribute, and other control types revert to settings specified by checked or selected attributes.

Once again, we’ve set up a lab page to demonstrate this difference. Locate the file chapter9/form/lab.reset.and.clear.html, and display it in your browser. You should see the display shown in figure 9.2.

Figure 9.2. The Clear and Reset Laboratory shows us the difference between a reset and a clear.

Note that this familiar form has been initialized with values via its HTML markup. The text field and text area have been initialized via their value attributes, the dropdown has had one of its options selected, and one check box and one radio button have been checked.

Click the Clear Form button, and watch what happens. The text field and text area are cleared, the dropdown has no selection, and all check boxes and radio buttons are unchecked.

Now click the Reset Form button, and note how the controls all revert to their original values. Change the values of each control, and click Reset Form, noting how, once again, the original values are restored.

The syntaxes for these commands are as follow:


Command syntax: clearForm

clearForm()

Clears the value of any controls in the wrapped set or that are descendants of elements in the wrapped set

Parameters

  • none

Returns

The wrapped set



Command syntax: resetForm

resetForm()

Calls the native reset() method of forms in the wrapped set

Parameters

  • none

Returns

The wrapped set


Now let’s see how the Form Plugin helps us to submit forms via Ajax requests.

9.1.3. Submitting forms through Ajax

Back in chapter 8, we saw how easy jQuery makes initiating Ajax requests, but the Form Plugin makes things even easier. We could use the serialization commands introduced in section 9.1.1, but wait! There’s more! The Form Plugin makes it even easier to hijack form requests.

The Form Plugin introduces two new commands for submitting forms via Ajax: one that initiates an Ajax request under script control, passing data in a target form as the request’s parameters, and another that instruments any form to reroute its submission as an Ajax request.

Both approaches use the jQuery Ajax core functions to perform the Ajax request, so all the global jQuery hooks continue to be applied even when using these methods in place of the core jQuery Ajax API.

Let’s start by examining the first approach.

Grabbing form data for an Ajax request

When we developed the e-commerce examples of chapter 8, we encountered a number of situations in which we needed to grab values from form controls to send them to the server via an Ajax request—a common real-world requirement. We saw that the core Ajax function made this a simple affair, particularly when we only needed to grab a handful of form values.

The combination of the Form Plugin’s serializeForm() method and the core Ajax functions makes submitting all the controls in a form even easier. But even easier than that, the Form Plugin makes submitting an entire form through Ajax almost trivial with the ajaxSubmit() command.

This command, when applied to a wrapped set containing a form, grabs the names and values of all the successful controls in the target form and submits them as an Ajax request. We can supply information on how to make the request to the method, or we can allow the request to default from the settings on the target form.

Let’s look at its syntax.


Command syntax: ajaxSubmit

ajaxSubmit(options)

Generates an Ajax request using the successful controls within the form in the wrapped set. The options parameter can be used to specify optional settings, or these settings can be defaulted as described in the following table.

Parameters

options

(Object|Function) An optional object hash containing properties as described in table 9.1. If the only desired option is a success callback, it can be passed in place of the options hash.

Returns

The wrapped set.


The options parameter can be used to specify exactly how the request is to be made. The optional properties are described in table 9.1, and all properties have defaults designed to make it easy to generate requests with the minimum of fuss and bother. It’s common to call this method with no options and let all the defaults apply.

Table 9.1. The optional properties for the ajaxSubmit() command, listed according to likelihood of use

Name

Description

url

(String) The URL to which the Ajax request will be submitted. If omitted, the URL will be taken from the action attribute of the target form.

type

(String) The HTTP method to use when submitting the request, such as GET or POST. If omitted, the value specified by the target form’s method attribute is used. If not specified and the form has no method attribute, GET is used.

dataType

(String) The expected data type of the response, which determines how the response body will be post-processed. If specified, it must be one of the following:

  • xml—Treated as XML data. Any success callback will be passed the responseXML document.
  • json—Treated as a JSON construct. The JSON is evaluated, and the result is passed to any success callback.
  • script—Treated as JavaScript. The script will be evaluated in the global context.

If omitted, no post-processing of the data (except as specified by other options such as target) takes place.

target

(String|Object|Element) Specifies a DOM element or elements to receive the response body as content. This can be a string depicting a jQuery selector, a jQuery wrapper containing the target elements, or a direct element reference. If omitted, no element receives the response body.

beforeSubmit

(Function) Specifies a callback function invoked prior to initiating the Ajax request. This callback is useful for performing any pre-processing operations including the validation of form data. If this callback returns the value false, the form submission is cancelled.

This callback is passed the following three parameters:

  • An array of the data values passed to the request as parameters. This is an array of objects; each contains two properties, name and value, containing the name and value of a request parameter.
  • The jQuery matched set that the command was applied to.
  • The options object that was passed to the command.

If omitted, no pre-processing callback is invoked.

success

(Function) Specifies a callback invoked after the request has completed and returned as response with successful status.

This callback is passed the following three parameters:

  • The response body as interpreted according to the dataType option.
  • A string containing success.
  • The jQuery matched set that the command was applied to.

If omitted, no success callback is invoked.

If this is the only option to be specified, this function can be passed directly to the command in place of the options hash.

Note that no provisions have been made for a callback upon error conditions.

clearForm

(Boolean) If specified and true, the form is cleared after a successful submission. See clearForm() for semantics.

resetForm

(Boolean) If specified and true, the form is reset after a successful submission. See resetForm() for semantics.

semantic

(Boolean) If specified and true, the form parameters are arranged in semantic order. The only difference this makes is in the location of the parameters submitted for input element of type image when the form is submitted by clicking that element. Because there’s overhead associated with this processing, this option should be enabled only if parameter order is important to the server-side processing and image input elements are used in the form.

other options

Any options that are available for the core jQuery $.ajax() function, as described in table 8.2, can be specified and will pass through to the lower-level call.

Despite the number of options, calls to ajaxSubmit() are frequently quite simple. If all we need to do is submit the form to the server (and don’t have anything to do when it completes), the call is as Spartan as

$('#targetForm').ajaxSubmit();

If we want to load the response into a target element or elements:

$('#targetForm').ajaxSubmit( { target: '.target' } );

If we want to handle the response on our own in a callback:

$('#targetForm').ajaxSubmit(function(response){
/* do something with the response */
});

And so on. Because there are sensible defaults for all options, we only need to specify as much information as needed to tune the submission to our desires.


Warning

Because the options hash is passed to the beforeSubmit callback, you might be tempted to modify it. Tread carefully! It’s obviously too late to change the beforeSubmit callback because it’s already executing, but you can add or change other simple settings like resetForm or clearForm. Be careful with any other changes; they could cause the operation to go awry. Please note that you can’t add or change the semantic property because its work is already over by the time the beforeSubmit callback is invoked.


If you were wondering if a lab page had been set up for this command, wonder no more! Bring up the page chapter9/form/lab.ajaxSubmit.html in your browser, and you’ll see the display in figure 9.3.

Figure 9.3. The ajaxSubmit Laboratory lets us play around with the workings of the ajaxSubmit() method.


Note

Note that, because we’re going to be submitting requests to the server, you must run this page under an active web server as described for the examples of chapter 8 in section 8.2.


This lab presents a now-familiar form that we can operate upon with the ajaxSubmit() command. The topmost pane contains the form itself; the middle pane contains a control panel that allows us to add the resetForm or clearForm options to the call; and a results pane will display three important bits of information when the command is invoked—the parameter data that was submitted to the request, the options hash that was passed to the command, and the response body.

If you care to inspect the code of the lab, you’ll note that the first two items of information are displayed by a beforeSubmit callback, and the third by the target option. (For clarity, the beforeSubmit function isn’t shown as part of the options display.)

When the Test button is clicked, a request is initiated via an ajaxSubmit() command applied to a wrapped set containing the form of the first pane. The URL of the request defaults to the action of that form: reflectData.jsp, which formats an HTML response depicting the parameters passed to the request.

Leaving all controls as they are upon initial load, click the Test button. You’ll see the results as shown in figure 9.4.

Figure 9.4. The Results pane shows us the data sent to the request, the options used to invoke the command, and the response body reflecting the data passed to the server resource.

The Submitted data, as expected, reflects the names and values of all successful controls; note the absence of unchecked check boxes and radio buttons. This perfectly mimics the submission of data that would occur if the form were to be submitted normally.

The Options used to make the request are also shown, allowing us to see how the request was made as we change the options in the Control Panel. For example, if we check the Reset Form check box and click Test, we’ll see how the resetForm option has been added to the method call.

The parameters detected by the server-side resource (by default, a JSP) are shown last. We can compare the response with the Submitted data to make sure that they always jive.

Run through various scenarios in the lab, changing form data and options to suit your whims, and observe the results. This should allow you to get a good understanding of how the ajaxSubmit() method operates.

In this section, we’ve assumed that we want to initiate a request using a form’s data under script control. We’d want to do this when an event other than a normal semantic submission event takes place—perhaps, clicking a button other than a submit button (as in the lab page) or a mouse event such as the one we used to invoke The Termifier requests in the examples of chapter 8. But sometimes, perhaps most often, the request submission will be the result of a normal semantic submission event.

Let’s see how the Form Plugin helps us set that up.

Hijacking a form’s submission

The ajaxSubmit() method is great for those times when we want to initiate a request under script control as a result of an event other than a form submission; but, often, we want to take a conventional form submission and hijack it, sending it to the server as an Ajax request rather than the usual full-page refresh.

We could leverage our knowledge of event handling and the ajaxSubmit() command to reroute the submission ourselves. As it turns out, we won’t have to; the Form Plugin anticipates this need with the ajaxForm() method.

This method instruments the form so that the submission is blocked when the form is submitted through one of the normal semantics events (such as clicking a submit button or pressing the Enter key when the form has focus) and an Ajax request that emulates the request is initiated.

ajaxForm() uses ajaxSubmit() under the covers, so it’s not surprising that their syntaxes are similar.


Command syntax: ajaxForm

ajaxForm(options)

Instruments the target form so that when submission of the form is triggered, the submission reroutes through an Ajax request initiated via the ajaxSubmit() command. The options parameter passed to this method is passed on to the ajaxSubmit() call.

Parameters

options

(Object|Function) An optional object hash containing properties as described in table 9.1. If the only desired option is a success callback, it can be passed in place of the options hash.

Returns

The wrapped set.


Typically, we apply ajaxForm() to a form in the ready handler; then, we can forget about it and let the command apply instrumentation to reroute the form submission on our behalf.

It’s possible, indeed customary, to declare the markup for HTML forms as if they are going to be submitted normally and to let ajaxForm() pick up these values from the declaration of the form. For times when users have disabled JavaScript, the form degrades gracefully and submits normally without us having to do anything special whatsoever. How convenient!

If, at some point after a form has been bound with ajaxForm(), we need to remove the instrumentation to let the form submit normally, the ajaxFormUnbind() command will accomplish that.

For fans of the lab pages, an ajaxForm Laboratory can be found in the file chapter9/form/lab.ajaxForm.html. Loaded into a browser, this page will appear as shown in figure 9.5.

Figure 9.5. The ajaxForm Laboratory page allows us to observe the hijacking of form submission to an Ajax request.


Command syntax: ajaxFormUnbind

ajaxFormUnbind()

Removes the instrumentation applied to the form in the wrapped set so that its submission can occur normally

Parameters

  • none

Returns

The wrapped set


This lab looks and works a lot like the ajaxSubmit Laboratory with a few important changes:

  • The Test button has been removed and the Submit me! button has been added to the form.
  • The Control Panel allows us to specify whether the semantic property is added to the options.
  • An input element of type image has been added so that we can observe the difference in behavior that occurs when semantic is set to true.

This form can be submitted in the following three ways:

  • Clicking the Submit me! button
  • Pressing the Enter key while the focus is on a focusable element
  • Clicking the Input image control (hibiscus blossom)

In any of these cases, you’ll see that the page isn’t refreshed; the form submission is rerouted through an Ajax request whose results are shown in the bottom pane of the page. Once again, play around with the controls on this page to become familiar with how the ajaxForm() command operates. When you have it down, we have one more Form Plugin subject to tackle.

9.1.4. Uploading files

A somewhat hidden, but useful, feature of the Form Plugin is its ability to automatically detect and deal with forms that need to upload files specified by input elements of type file. Because XHR is unable to accommodate such requests, the ajaxSubmit() command (and by proxy ajaxForm()) reroutes the request to a dynamically created and hidden <iframe>, while setting the content type of the request correctly as multipart/form-data.

The server code must be written to handle such file upload requests and multipart forms; but, from the viewpoint of the server, the request looks like any other multipart request generated by a conventional form submission. And from the perspective of the page code, this works exactly like a regular ajaxSubmit().

Bravo!

Now let’s set our sights on another useful jQuery plugin.

9.2. The Dimensions Plugin

Knowing the exact position and dimensions of an element is sometimes key to creating Rich Internet Applications. For example, when implementing dropdown menus, we want the menu to appear in a precise position in relation to its triggering element.

Core jQuery has the width(), height(), and offset() commands but lacks the ability to precisely locate an element in all circumstances. That’s where the Dimensions Plugin comes in.

Let’s take a run through its API.

9.2.1. Extended width and height methods

The Dimensions Plugin extends the core width() and height() commands so that they can be used to obtain the width or height of the window and document objects; something the core commands can’t do. The syntaxes for these extended commands are as follow:


Command syntax: width

width()

Returns the width of the first element, window, or document object in the wrapped set. If the first wrapped element isn’t the window or the document, the core jQuery command is called.

Parameters

  • none

Returns

The width of the window, document, or element.



Command syntax: height

height()

Returns the height of the first element, window, or document object in the wrapped set. If the first wrapped element isn’t the window or the document, the core jQuery command is called.

Parameters

  • none

Returns

The height of the window, document, or element.


These extended commands don’t interfere with the corresponding core commands when passed a value as a parameter (in order to set the width or height of elements), except when the first element is the window or document element. In such cases, the commands act as if no parameter was passed and the width or height of the window or document is returned. Be warned, and code accordingly.

The width() and height() commands return the dimensions assigned to the content of an element, but sometimes we want to account for other aspects of the box model, such as any padding or border applied to the element. For such occasions, the Dimensions Plugin provides two sets of commands that take these other dimensions into account.

The first of these, innerWidth() and innerHeight(), measure not only the content of the element but any padding applied to it as well. The second set, outerWidth() and outerHeight(), include not only the padding but also any border and, optionally, margins.


Command syntax: innerWidth and innerHeight

innerWidth()

innerHeight()

Returns the inner width or height of the first element in the wrapped set. The inner dimension includes the content and any padding applied to the element.

Parameters

  • none

Returns

The inner width or height of the first element in the wrapped set.



Command syntax: outerWidth and outerHeight

outerWidth()

outerHeight()

Returns the outer width or height of the first element in the wrapped set. The outer dimension includes the content, any padding, and any border applied to the element.

Parameters

options

(Object) An object hash that accepts a single option, margin, which specifies whether margins should be accounted for in the calculation. The default is false.

Returns

The outer width or height of the first element in the wrapped set.


Note that, for all the inner and outer methods, specifying window or document have the same effect.

Now let’s learn about the other dimensions this plugin allows us to locate.

9.2.2. Getting scroll dimensions

As has long been true for user interfaces of all types, content doesn’t always fit in the space allotted to it. This issue has been addressed via the use of scrollbars, which allow users to scroll through all the content even if it can’t all be seen within a viewport at once. The web is no different; content frequently overflows its bounds.

We may need to know the scrolled state of the window or of content elements that allow scrolling when trying to place new content (or move existing content) in relation to the window or scrolled element. Additionally, we may want to affect the scrolled position of the window or scrolled element.

The Dimensions Plugin allows us to obtain or set the scrolled position of these elements with the scrollTop() and scrollLeft() methods.


Command syntax: scrollTop and scrollLeft

scrollTop(value)

scrollLeft(value)

Gets or sets the scroll dimensions for the window, document, or scrollable content element. Scrolled elements are content-containing elements with a CSS overflow, overflow-x, or overflow–y value of scroll or auto.

Parameters

value

(Number) The value, in pixels, to which the scroll top or left dimension is set. Unrecognized values are defaulted to 0. If omitted, the current value of the top or left scroll dimension is obtained and returned.

Returns

If a value parameter is provided, the wrapped set is returned. Otherwise, the requested dimension is returned.


Wrapping either window or document produces the same results.

Do you want to play with this in a lab page? If so, bring up the file chapter9/dimensions/lab.scroll.html, and you’ll see the display in figure 9.6.

Figure 9.6. The Scrolling Lab lets us observe the effects of the scrollTop() and scrollLeft() methods.

This lab page allows us to apply top and left scroll values to a test subject and to the window itself; it uses the getter version of the scrollTop() and scrollLeft() commands to display the scroll values of the scroll dimensions at all times.

The Lab Control Panel pane of this page contains two text boxes in which to enter numeric values to be passed to the scrollTop() and scrollLeft() commands, as well as three radio buttons that allow us to choose which target the commands are applied to. We can choose the Window, the Document, or the Test subject <div> element. Note that we set the height and width of the <body> element of the page to the ridiculous size of 2000 pixels square to force the window to show scrollbars.

The Apply button applies the specified values to the specified target, and the Restore button sets the scroll values for all targets back to 0. Below the buttons, a section shows the current values for the three targets in real time.

The Test subject pane contains the test subject: a 360 by 200 pixel <div> element that contains an image that’s much larger than can be displayed in that size. The CSS overflow value for this element is set to scroll, causing scrollbars to appear so that we can pan around the image.

Work through the following exercises using this page:

  • Exercise 1— Using the scrollbars on the Test subject, pan around the image. Watch the Results display, and note how the current scroll values are kept up to date. A scroll event handler established on that element calls the scrollTop() and scrollLeft() methods to obtain these values for display.
  • Exercise 2— Repeat the steps of exercise 1, except this time pan around the page using the window’s scrollbars. Watch the Results (unless you move them off-screen), and note how the window’s scroll values change as you pan around the page. Also, notice how the values for the Document stay in lockstep with those of the Window, emphasizing that, for the scroll methods, specifying either the window or the document performs the same action. We’ve included both the window and the document as targets to convince you of this point.
  • Exercise 3— Click the Restore button to set everything to normal. Select the Test subject as the target, and enter scroll values into the text boxes, such as 100 and 100. Click the Apply button. Oh! What a pretty waterfall! Test other values to see how they affect the Test subject when the Apply button calls the scrollTop() and scrollLeft() methods.
  • Exercise 4— Repeat exercise 3 with the Window as the target.
  • Exercise 5— Repeat exercise 3 with the Document as the target. Convince yourself that, whether you specify the Window or the Document as the target, the same thing happens in all cases.

9.2.3. Of offsets and positions

We might, at first, think that obtaining the position of an element is a simple task. All we need to do is to figure out where the element is in relation to the window origin, right? Well, no.

When the top and left CSS values are applied to an element, these values are in relation to the element’s offset parent. In simple cases this offset parent is the window (or, more precisely, the <body> element loaded into the window); but, if any ancestor of an element has a CSS position value of relative or absolute, the closest such ancestor is the element’s offset parent. This concept is also referred to as the positioning context of the element.

When determining the location of an element, it’s important to know which position we’re asking for. Do we want to know the position of the element in relation to the window origin or to its offset parent? Other factors can also be involved. For example, do we want dimensions such as border accounted for?

The Dimensions Plugin handles all of that for us, starting with obtaining the offset parent.


Command syntax: offsetParent

offsetParent

Returns the offset parent (positioning context) for the first element in the wrapped set. This is the closest ancestor with a position value of relative or absolute, or the <body> element if no such ancestor is found. This method should only be applied to visible elements.

Parameters

  • none

Returns

The offset parent element.


When we want to obtain the relative position of an element from its offset parent, we can use the position() command.


Command syntax: position

position()

Returns the position values (top and left) of the first element in the wrapped set relative to its offset parent.

Parameters

  • none

Returns

An object with two properties, top and left, containing the position values of the element relative to its positioning context (offset parent).


This command is useful for when we want to reposition an element in relation to its current location, but sometimes we want to know the position of an element in relation to the <body> element (regardless of what its offset parent is) and to have a little more control over how the calculation is made. For those times, the Dimensions Plugin provides the offset() command.


Command syntax: offset

offset(options,results)

Returns offset information for the first element in the wrapped set. By default, the information is relative to the <body> element, and the manner in which it’s calculated is controlled by the settings in the options parameter.

Parameters

options

(Object) An object hash containing settings that control how the method performs its calculations. The possible values are as follows:

  • relativeTo—(Element) Specifies an ancestor element of the wrapped element to base the relative offset on. This element should have a position value of relative or absolute. If omitted, the default is the <body> element.
  • lite—(Boolean) Specifies that certain browser-specific optimizations be skipped in the calculations. This will increase performance at the price of accuracy. Defaults to false.
  • scroll—(Boolean) Specifies whether scroll offsets should be taken into account. Defaults to true.
  • padding—(Boolean) Specifies whether padding should be included in the calculation. Defaults to false.
  • border—(Boolean) Specifies whether borders should be included in the calculation. Defaults to false.
  • margin—(Boolean) Specifies whether margins should be included in the calculation. Defaults to true.

results

(Object) An optional object to receive the results of the method. If omitted, a new object is created, populated with the results and returned as the value of the method. If specified, the passed object is augmented with the result properties, and the wrapped set is returned from the method. This is useful when you want the method to participate in a jQuery command chain.

Returns

The wrapped set if a results object is specified, the results object if not. The results object contains properties top and left, as well as scrollTop and scrollLeft unless the scroll option is explicitly set to false.


To ensure that the values returned from this method are accurate, we express dimensions and positions of the elements on the page in pixel values. The default settings for this method usually give an accurate representation; but, if we’re more interested in speed than in accuracy (for example, if we’re using this method on many elements in a tight loop), we might want to explore how the lite option and other settings work in our situation.

Let’s move away from the realm of positions and measurements and look at another plugin that’s helpful on pages with lots of dynamic elements and event handling.

9.3. The Live Query Plugin

If you’ve grokked some of the higher-level concepts presented in this book, you’ll have noted that jQuery has a profound effect on the structure of the pages that we write, using it to best advantage. Employing the precepts of Unobtrusive JavaScript, our pages usually consist of the HTML markup in the body and a ready handler that sets up the behavior of the page, including establishing the event handlers for the elements defined within the body.

Not only does jQuery make it incredibly easy to set up our pages in this way, it also makes it easy for us to change the page radically during its loaded lifetime. During the life cycle of the page, many DOM elements that didn’t exist when the ready handler was executed can later be added to the DOM tree. When adding such elements, we frequently must establish event handlers as we create the elements to define their behavior, as we did for the initially loaded elements. The novice web author might churn out lots of repeated, cut-and-pasted code, but more experienced developers factor out common elements into functions or JavaScript classes.

But wouldn’t it be nice if we could declare the behavior of all elements that will ever exist on the page in the ready handler regardless of whether they exist at page load or not?

Seems like a pipe dream, doesn’t it? But it’s not; the Live Query Plugin allows us to do just that!

Live Query lets us establish the following behaviors for DOM elements based on their match to a jQuery selector that we define:

  • Establish events handlers for elements that match the selector
  • Trigger a function to be executed when any element matches the selector
  • Trigger a function to be executed when any element no longer matches the selector

The Live Query Plugin also allows us to unbind any of these behaviors at any time.

We’ll start our overview of Live Query by looking at how it allows us to establish event handlers for DOM elements whether they exist or not.

9.3.1. Establishing proactive event handlers

The Live Query Plugin allows us to establish event handlers in a proactive fashion—establishing event handlers on elements that match a jQuery selector now or at anytime in the future. The established handlers apply, not only to existing elements that match the selector when the handler is established, but also to any elements that might match the selector pattern later on in the life cycle of the page—including existing elements that might be changed to match the pattern and newly created elements that match.

When such elements are changed so that they no longer match the selector, handlers established by Live Query are automatically removed from those elements.

The changes that affect whether an element matches the selector pattern or not hinge on using jQuery methods. If the elements are mucked about with outside the realm of jQuery, obviously Live Query loses the hooks it needs to keep track of the elements. If we absolutely need to make changes outside jQuery’s control, Live Query does have a way to help us deal with that; we’ll get to that later.

All of the Live Query behaviors, including event listeners, are established on elements using the livequery() method. The format that establishes proactive event handlers is as follows:


Command syntax: livequery

livequery(event,listener)

Establishes a function as the event handler for the specified event type on all elements in the matched set and any elements that will match the selector of the matched set at a later point.

Parameters

event

(String) The type of event for which to establish the listener. This is the same set of events as used with the jQuery bind() command.

listener

(Function) The function to establish as the event listener. The function context (this) for each invocation is the matched element.

Returns

The wrapped set.


This form of livequery() is called exactly like the jQuery bind() command. Like bind(), it establishes the handler for all elements in the matched set. But it also automatically establishes the handler on any elements that match the selector pattern at any time while the page is loaded. It also unbinds the listener from any elements, including those from the original matched set, that no longer match the pattern.

This is immensely powerful. It allows us to set up the behavior of elements that match a selector of our choosing once in the ready handler, without having to worry about keeping track of such things later as elements are changed or added to the page. How cool is that?

The establishment of event handlers is a special case—a common one, which is why it gets special attention—of performing actions when elements are changed (or added) so that they match or no longer match the original selector pattern. We might like to do a multitude of other things at such points, and Live Query doesn’t disappoint us.

9.3.2. Defining match and mismatch listeners

If we want to perform an action (other than binding or unbinding event handlers) when elements make a transition into or out of the state of matching a particular selector, we can use another form of the livequery() command.


Command syntax: livequery

livequery(onmatch,onmismatch)

Establishes callback functions invoked when elements transition into or out of the state of matching the selector for the matched set.

Parameters

onmatch

(Function) Specifies a function that serves as the match listener. This function is invoked for any element (established as the function context) that transitions into the matched state. If any existing elements match at the time of this method call, the function is called immediately for each such element.

onmismatch

(Function) Specifies an optional function that serves as the mismatch listener. This function is invoked for any element (established as the function context) that transitions out of the matched state. If omitted, no mismatch listener is established.

Returns

The wrapped set.


If we only want to establish the optional mismatch listener, we can’t do so by passing null as the first parameter to this method because this causes the second parameter to be established as the match listener just as if it had been passed as the first argument. Instead, we pass in a no-op function as the first parameter:

$('div.whatever').livequery(
function(){},
function(){ /* mismatch actions go here */ }
);

As with the event listeners established by Live Query, the change causing the transition into or out of the matched state automatically triggers these functions when the change is performed by a jQuery method. But what about those times when we can’t use jQuery for such changes?

9.3.3. Forcing Live Query evaluation

If we effect changes to elements that cause them to transition into or out of the matched state for Live Query listeners that we’ve established through means other than jQuery functions, we can force Live Query to trigger its listeners with a utility function.


Function syntax: $.livequery.run

$.livequery.run()

Forces Live Query to perform a global evaluation of elements, triggering any appropriate listeners. This is useful when changes to elements are made outside the control of jQuery methods.

Parameters

  • none

Returns

Undefined.


We’ve seen that Live Query automatically removes event listeners when an element leaves the matched state and that we can establish a mismatch listener to do whatever we want on such mismatch transitions. But what do we do when we want to take a sledgehammer to the listeners?

9.3.4. Expiring Live Query listeners

In the same way that jQuery provides an unbind() command to undo the action of bind(), Live Query provides its own means to undo the establishment of Live Query event handlers and match/mismatch handlers—the expire() command, which sports many parameter formats.


Command syntax: expire

expire()

expire(event,listener)

expire(onmatch,onmismatch)

Removes listeners associated with the selector of the match set. The format without parameters removes all listeners associated with the selector. See the description of the parameters below for how they affect this command.

Parameters

event

(String) Specifies that event listeners for the event type be unbound. If no listener is specified, all listeners for the event type are removed.

listener

(Function) When specified, only the specific listener is unbound from the selector (for the specified event type).

onmatch

(Function) Specifies the match listener that’s to be unbound from the selector.

mismatch

(Function) If present, specifies the mismatch listener to be unbound from the selector.

Returns

The wrapped set.


We’ve provided a lab page to help illustrate the use of these techniques. Bring up the file chapter9/livequery/lab.livequery.html in your browser, and you’ll see the display of figure 9.7.

Figure 9.7. The Live Query Lab lets us observe Live Query in action.

This lab page displays three panes: the Control Panel with buttons that do interesting things, a Test Subjects container, and the Console, which displays messages to let us know what’s going on.

The setup for this page bears some explanation. In the ready handler, the Control Panel buttons are instrumented to perform their respective actions once clicked (refer to the file for details if interested), and two Live Query statements are executed:

The first of these statements establishes a Live Query event handler for all <div> elements with the class testSubject . These elements include the single test subject already resident when the page is loaded (see figure 9.7), as well as all future test subject elements that will be created after clicking the Add New Test Subject button. Not only is the click event handler (whose activity we’ll discuss in a minute) immediately established on the existing test subject element, but the click handler will automatically be added to any future test subjects dynamically added to the page (which will all be created as <div> elements with class testSubject).

The click handler causes the class matched to be toggled for the target of the event. To make it easy to see which test subjects have this class and which do not, we set up CSS rules so that elements without the class have a black border and white background, and elements with the class are rendered with a thicker maroon border and khaki background. We’re all about trendy Web 2.0 colors!

The second of these statements establishes match and mismatch handlers for all <div> elements with the class matched . Each of these handlers issues a message to the Console, announcing that an element has become matched or mismatched respectively. Because no elements on the page possess the matched class at page load, the Console is empty when the page is initially displayed.

Now, let’s see what the Control Panel buttons do:

  • Add New Test Subject— This button adds a new test subject <div> element to the page. The element is created with an id of testSubject#, where # is a running count, and a class of testSubject. One such element is pre-populated in Test Subjects via HTML markup.
  • Expire Match Handlers— This button executes the statement $('div.matched').expire();, which causes the match and mismatch handlers we established in the ready handler to expire.
  • Expire Event Handler— This button executes the statement $('div.testSubject').expire();, which causes the proactive event handler we established in the ready handler to expire.

Now that we understand how the lab is wired, let’s run through some exercises:

  • Exercise 1— Load the page, and click within the bounds of Test Subject 1. Because the Live Query event handler for the click event that we established causes the matched class to be toggled (in this case added) to the element, we see that the element changes colors as displayed in figure 9.8. Additionally, because the addition of the matched class causes the element to match the selector we used to establish the match and mismatch handlers, we see that the match handler has fired and written a message to the Console.
    Figure 9.8. The addition of the matched class to the test subject triggers a change in rendition, as well as the established match handler.

  • Exercise 2— Click Test Subject 1 again. This toggles the matched class, removing it from the element. The element returns to its original appearance, and the mismatch handler is triggered because the element no longer matches the selector, resulting in a Console message to that effect.
  • Exercise 3— Click the Add New Test Subject button. A new test subject <div> element is added to the page. Because this element is created with the class of testSubject, it now matches the selector used to establish the proactive click handler that toggles the matched class. This triggers Live Query to automatically bind the click handler to this new element (the code to add this element doesn’t bind any handlers to the newly created element). To test this supposition, click the newly created Test Subject 2. We see that it changes rendition and that a match handler has been called on its behalf, proving that the click handler for toggling the matched class of the element was automatically added to the newly created element. See the evidence in figure 9.9.
    Figure 9.9. The fact that the newly added Test Subject 2 reacts to clicks in the same way as Test Subject 1 proves that Live Query has automatically added the click handler, as well as the match and mismatch handlers, to the newly created element.

  • Exercise 4— Experiment with the Add New Test Subject button and Test Subjects until you’re convinced that the event, match, and mismatch handlers are always automatically added to the test subject elements whenever appropriate.
  • Exercise 5— Play around with expiring Live Query handlers. Reload the page so that you start with fresh settings, and add a test subject or two to the page with the Add New Test Subject button. Now click the Expire Match Handlers button, which expires the match and mismatch handlers that were established on the Test Subjects. Notice that, when you click the Test Subjects, no match/mismatch messages appear in the Console, proving that the handlers have been removed. The click event handler still toggles the matched class because the element still changes appearance when clicked.
  • Exercise 6— Click the Expire Event Handler button. This expires the Live Query click handler for the Test Subjects. Note that the Test Subjects are now unresponsive to mouse clicks and that they retain the state they had when you clicked the button.

It doesn’t take much imagination to see the power that this plugin brings to pages in Rich Internet Applications where elements are changing all the time, including popping into and out of existence. By allowing us to establish the behaviors of these events up front, the Live Query Plugin helps us minimize the amount of code we need to write when changing and adding elements to the page.

Now, let’s move on to one more important and useful plugin.

9.4. Introduction to the UI Plugin

When it comes to Rich Internet Applications, the UI is king. It’s not surprising that many jQuery plugins focus on enabling rich user interfaces. In this section, we’ll introduce the official UI Plugin, an important and recent addition to the jQuery family. Because it’s an important component, we’d love to cover this plugin to the same depth that we examined core jQuery; but reality intervenes, and practical space considerations prevent more extensive coverage.

We’ll extensively cover two of the essential methods defined by this plugin—the ones that provide support for drag-and-drop on our pages—giving you a good feel for how the remainder of the plugin operates. Then, we’ll provide an overview of the remainder of the plugin to demonstrate what it can do to bring Rich Internet Application functionality to our pages. For more details regarding these areas, please visit http://docs.jquery.com/ui.

The UI Plugin provides three major areas of support: mouse interaction, widgets, and visual effects. The drag-and-drop operations fall under the category of mouse interaction; that’s where we’ll start.

9.4.1. Mouse interactions

Interacting with the mouse pointer is an integral and core part of any GUI. Although many simple mouse pointer interactions are built into web interfaces (clicking, for example), the web doesn’t natively support some advanced interaction styles available to desktop applications. A prime example of this deficiency is the lack of support for drag-and-drop.

Drag-and-drop is an ubiquitous interaction technique for desktop user interfaces. For example, in the GUI file manager for any desktop system, we easily copy files or move them around the filesystem by dragging and dropping them from folder to folder or even delete them by dragging and dropping them onto a Trash or Wastebasket icon. But as prevalent as this interaction style is within desktop applications, it’s as sparse in web applications, mainly because modern browsers don’t natively support drag-and-drop. Correctly implementing it is a daunting task.

“Daunting?” you scoff. “A few captured mouse events and some CSS fiddling. What’s the big deal?”

Although the high-level concepts aren’t that difficult to grasp, it turns out that implementing the nuances of drag-and-drop support, particularly in a robust and browser-independent manner, can become painful quickly. But in the same way that jQuery and its plugins have eased our pain before, they do so again with support for web-enabled drag-and-drop.

But before we can drag and drop, we first need to learn how to drag.

Dragging things around

Although we’d be hard-pressed to find the term draggable in most dictionaries, it’s the term that’s commonly applied to items that can be dragged about in a drag-and-drop operation. Likewise, it’s the term that the UI Plugin uses to describe such elements and as the name of the method that applies this ability to elements in a matched set.


Command syntax: draggable

draggable(options)

Makes the elements in the wrapped set draggable according to the specified options.

Parameters

options

(Object) An object hash of the options to be applied to the draggable elements, as described in table 9.2. With no options specified, the elements are freely draggable anywhere within the window.

Returns

The wrapped set.


We must include at least the two following files to use the draggable() command (in addition to the core jQuery script file):

  • ui.mouse.js
  • ui.draggable.js

To obtain extended options, we also include the following:

  • ui.draggable.ext.js

The options, both basic and extended, supported by this method are shown in table 9.2.

Table 9.2. Basic and extended options for the draggable() command

Name

Description

Basic options

 

helper

(String|Function) Specifies exactly what is to be dragged. If specified as original (the default), the original item is dragged. If clone is specified, a copy of the element is created for dragging. You can also specify a function that accepts the original DOM element as its parameter and returns an element to be dragged. This is most often a clone of the original element with a transformation of some type applied—for example, function(e){return$(e).clone().css('color','green')}.

ghosting

(Boolean) If true, a synonym for helper:'clone'.

handle

(jQuery|Element) An alternate element, or jQuery wrapped set containing an element, that serves as the drag handle—the item clicked on to initiate the drag operation. This element is frequently a child element of the draggable but can be any element on the page.

preventionDistance

(Number) The number of pixels that the mouse pointer needs to be moved after a click for a drag operation to commence. This can be used to help prevent accidental dragging. If omitted, the default is 0.

dragPrevention

(Array) An array of selectors of child elements that shouldn’t initiate a drag operation when clicked. The default is ['input','textarea','button','select','option']. This is useful for preventing the start of drag operation when an embedded control is clicked, for example.

cursorAt

(Object) Specifies the spatial relationship between the mouse pointer and the draggable object while a drag operation is under way. The specified object can define properties of top, left, bottom or right. For example, an object of {top:5,left:5} causes the pointer to be positioned 5 pixels from the upper-left corner of the dragged element. If omitted, the pointer maintains its original relative position at the point of the mouse click that initiates the drag.

appendTo

(String|Element) Specifies an element that the dragged helper is appended to at the end of the drag operation. Specifying the string parent (the default) leaves the helper in its original hierarchy.

start

(Function) A callback function called when a drag operation starts. Its function context (this) is set to the draggable element, and it’s passed two parameters: the event instance in which the target property is set to the draggable element and an object containing the following properties:

  • helper—Current helper element
  • position—Object containing properties top and left, specifying the position of the mouse at the start of the drag operation
  • offset—Object specified for cursorAt
  • draggable—Internal JavaScript draggable object (not very useful)
  • options—Options hash used to create the draggable

stop

(Function) A callback function called when the drag operation completes. It’s passed the same two parameters as the start callback. The position property of the second parameter reports the location of the upper-left corner of the draggable.

drag

(Function) A callback function continuously invoked while a drag operation is underway. It’s passed the same two parameters as the start callback. The position property of the second parameter reports the location of the upper-left corner of the draggable.

Extended options

 

axis

(String) Constrains the axis along which the draggable can be moved: x for the horizontal axis and y for the vertical axis. If omitted, no axis constraints are imposed.

containment

(String|Object|Element) Specifies the bounds within which the draggable can be moved. If omitted, no containment is imposed. Can be specified as the following:

  • parent—Contains the draggable within its parent so that no scrollbars need be added to the parent
  • document—Contains the draggable within the current document so that no scrollbars need be added to the window
  • a selector—Identifies the containing element
  • an object—Specifies a bounding rectangle relative to the parent with the properties left, right, top, and bottom

effect

(Array) An array of two strings that applies a fade effect to cloned helpers. Can be specified as ['fade','fade'], ['fade',''], or ['','fade']. This may seem like an odd way to specify the effects, but it allows for future support for additional effects types; currently, only fade is supported.

grid

(Array) An array of two numbers that specify a rectangular grid defining discrete locations that the draggable can be moved to—for example, [100,100]. The origin of the grid is relative to the original location of the draggable. If omitted, no grid constraint is placed on movement.

opacity

(Number) Specifies the opacity of the dragged helper during the drag operation as a value between 0.0 and 1.0 (inclusive). If omitted, the opacity of the dragged helper is unchanged.

revert

(Boolean) If true, the draggable is moved back to its original position when the drag operation concludes. If omitted or specified as false, the location isn’t reverted.

If you thought we were going to pass up an opportunity for a fun lab page to demonstrate these options, guess again! But before we get to that, let’s take a look at the other three methods related to draggables.

If we want to make a draggable element no longer draggable, the draggableDestroy() command removes its draggability.


Command syntax: draggableDestroy

draggableDestroy()

Removes draggability from the elements in the wrapped set

Parameters

  • none

Returns

The wrapped set


If all we want to do is to temporarily suspend an element’s draggability and restore it at a later time, we disable draggability with draggableDisable() and restore it with draggableEnable().


Command syntax: draggableDisable

draggableDisable()

Suspends draggability of the wrapped draggable elements without removing the draggability information or options

Parameters

  • none

Returns

The wrapped set



Command syntax: draggableEnable

draggableEnable()

Restores draggability to any draggables in the matched set that have been disabled via draggableDisable()

Parameters

  • none

Returns

The wrapped set


Through the use of the UI Draggables Lab, let’s examine the draggable options. Bring up the page chapter9/ui/lab.draggables.html in your browser, and you’ll see the display of figure 9.10.

Figure 9.10. The UI Draggables Lab page allows us to play around with most of the options available for draggable items.

This lab page sports a now-familiar layout: a Control Panel pane contains controls that allow us to specify the options for draggable(), a Test Subject pane contains an image element to serve as the draggable test subject, and a Console pane reports information about an ongoing drag operation.

When the Apply button (found in the Control Panel) is clicked, the specified options are collected and a draggable() command is issued. The format of the command is displayed below the Apply button. (For clarity, only the options specified via the Control Panel are displayed. The callbacks added to the options to effect the display in the Console pane aren’t shown but are included in the command that’s issued.) You’ll observe the actions of the Disable and Enable buttons in exercise 3. The Reset button restores the option controls to initial conditions and destroys any draggable capability set on the test subject.

Let’s dig into this lab and start some exercises!

Exercise 1— For the first exercise, we’ll create a simple draggable with all options defaulted. Bring up the UI Draggables Lab page in your browser, and leave all option controls as they are upon load; they are set so that their initial conditions specify no options.

Try to click and drag the Test Subject dragon image. Nothing much happens unless you’re using OS X, in which case you will see something happen. OS X allows you to drag images off of web pages to copy them to your local system via drag-and-drop. Don’t confuse this system-enabled drag-and-drop with the operations we’re going to enable on our pages.

Now, click the Apply button, and observe that the executed command is displayed as follows:

$('#testSubject').draggable({});

Try dragging the dragon image again. Note how you can make the dragon fly around the browser window. (No flapping wings though—that’d be a more advanced animation!) Also, note how you can move the image to the edges of the window and, when moved to the extreme right, it causes a horizontal scrollbar to appear where none was before (in most browsers).

Drop the dragon, and pick him up again. Move him around as many times as you like. Observe how the values in the console are kept up to date during a drag operation. This is effected using the start, stop, and drag callbacks.

Exercise 2— Reload the page to restore initial conditions. If you’re using Firefox or Camino, these browsers have an annoying feature: Form controls aren’t restored to initial conditions when you reload a page using the Reload toolbar button. To cause the page to reload to initial conditions, move the text focus to the URL address field and hit the Enter key.

Now, set the helper option to Original, click the Apply button, and drag the Test Subject image around the window. You should notice no difference from the behavior of exercise 1 because Original is the default setting when helper is Unspecified. Change the value to Clone, and click Apply.

Now when you drag the image, you see a copy of the image being dragged about rather than the original element. Once you conclude the drag, the clone disappears.

Exercise 3— Leaving everything as you left it at the end of exercise 2, click the Disable button, and note the command that’s issued:

$('#testSubject').draggableDisable();

Try to drag the dragon. Nothing happens. Now click the Enable button, which issues the following command:

$('#testSubject').draggableEnable();

Note that you can drag again and that the original options (in this case the clone helper) are still in effect, demonstrating the difference between draggableDestroy(), which removes drag capability completely, and draggableDisable(), which only suspends it until draggableEnable() is called.

Exercise 4— Reset the Lab, and choose True for the revert option, and click Apply. Drag the test subject, and note how it moves back to its original location when the operation concludes. Now, select Clone for the helper, click Apply, and repeat the exercise. Note that revert is applied to the clone.

Exercise 5— Reset the Lab, and experiment with the setting of the axis option. You can use this option to constrain the movement during a drag to the horizontal or vertical planes.

Exercise 6— In this exercise, we’ll turn our attention to the containment option. You’ll want to increase the height of your browser window to as much as your screen will allow; hopefully, your resolution will cause some extra space to be shown below the Console pane.

Up to this point, we’ve left containment unspecified. Recall how you were able to move the dragon anywhere within the browser window. Now choose Document, and click Apply. When you drag the image note two important things:

  • You can no longer move the image beyond the edges of the window, so no scrollbars appear where there were previously none.
  • You can’t move the image below the bottom of the Console pane where the document stops but the window doesn’t.

Now change the setting to Parent, and click Apply. When a drag operation is started, note how you can only drag the image around the inside of the Test Subject pane (a <fieldset> element), which is the parent of the test subject element. Note, also, that this is true even if the drag operation started outside the parent (as a result of a previous drag operation that was not constrained to the parent).

Exercise 7— Choose a helper option of Clone, and observe the effect of the Effect option on the helper in its various settings.

Exercise 8— Reset the Lab, and specify an Opacity of 0.5. Observe how the opacity of the dragged element is affected whether the original element or a helper clone is being dragged.

Exercise 9— Reset the Lab, and set the preventionDistance option to a large value such as 200. After clicking Apply, start a drag operation by clicking the edge of the dragon’s left wing and moving the mouse pointer to the right. You traverse almost the entire width of the dragon (whose image width is 250 pixels) before the drag operation starts. It would be rare to set this option to such a large value, but we did so here for illustration of the behavior of the option. More often, this would be set to a much smaller value to prevent accidental movements of a few pixels from initiating an unintended drag operation.

Exercise 10— Reset the Lab, and specify grid values of 100 and 100. After clicking Apply, note how the image can now only be dragged in discrete movements of 100 pixels in either direction. Play around with other values to observe their behavior on the drag movement.

Exercise 11— Reset the Lab, and enter values of 10 and 10 for the cursorAt option. Click the Apply button. When a drag operation is started, the relative position of the image and mouse pointer is set so that the pointer is positioned 10 pixels in either direction, relative to the upper-left corner of the image (near the tip of the wing) no matter where the pointer was positioned within the image at the start of the drag.

Exercise 12— Go nuts! Play around with the settings of the lab, individually and in concert, until you feel confident that you understand how they each affect the drag operation of draggable elements.

Dragging things around the screen is all well and good, but is it really useful? It’s fun for a time, but like playing with a yo-yo (unless we’re true aficionados), it loses its charm quickly. In practical applications, we could use it to allow users to move modular elements around the screen (and if we’re nice, we’d remember their chosen positions in cookies or other persistence mechanisms), or in games or puzzles.

Drag operations truly shine when there’s something interesting to drop dragged elements on. Let’s see how we can make droppables to go with our draggables.

Dropping dragged things

The flip side of the coin from draggables is droppables—elements that can accept dragged items and do something interesting when such an event occurs. Creating droppable items from page element is similar to creating draggables; in fact, it’s even easier because there are fewer options to worry about.

And like draggables, droppables are split into two script files: the basic file that defines the droppable() command and its basic options and an option file that contains the extended options. These files are

ui.droppable.js
ui.droppable.ext.js

The syntax for the droppable() command is as follows:


Command syntax: droppable

droppable(options)

Establishes the elements in the wrapped set as droppables, or elements on which draggables can be dropped.

Parameters

options

(Object) The options applied to the droppable elements. See table 9.3 for details.

Returns

The wrapped set.


Once an element is instrumented as a droppable, it exists in one of three states: inactive, active, and armed.

Inactive state is the droppable’s normal state where it stays most of the time, waiting to detect when a drag operation starts. When a drag starts, the droppable determines if the draggable is a suitable element for dropping (we’ll discuss the concept of suitability in a moment) and, if so (and only if so), enters active state. In active state, the droppable monitors the drag operation, waiting until either the drag operation terminates, in which case the droppable returns to inactive state, or the draggable hovers over the droppable. When a suitable draggable element hovers over the droppable element, it enters armed state.

If the drag operation terminates while the droppable is in armed state, the draggable is considered to have been dropped onto the droppable. If the draggable continues to move so that it no longer hovers over the droppable, the droppable returns to active state.

Wow, that’s a load of state changes to keep track of! The diagram of figure 9.11 should help you keep it all straightened out.

Figure 9.11. As a suitable draggable moves about the page, the droppable moves between its various states.

As with draggables, a basic set of options is available in the primary script file, and a set of extended options is available if the additional script file is included. Both sets of options are described in table 9.3.

Table 9.3. Basic and extended options for the droppable() command

Name

Description

Basic options

 

accept

(String|Function) Specifies which draggables are suitable for dropping on the droppables. This can be a string describing a jQuery selector or a function that returns true to specify that a draggable is acceptable. When a function is specified, it’s invoked with the candidate draggable passed as its only parameter.

tolerance

(String) A string value that defines how a draggable must be positioned in relation to the droppable in order to arm the droppable. The possible values are as follow:

  • touch—Arms the droppable if the draggable touches the droppable, or if any part of the draggable overlaps the droppable
  • pointer—Arms the droppable if the mouse pointer enters the droppable during a drag operation
  • intersect—Arms the droppable if 50% of the draggable intersects the droppable
  • fit—Arms the droppable if the draggable is completely contained within the droppable

activate

(Function) A callback function invoked when a drag operation for an acceptable draggable commences—when the droppable makes a transition from inactive to active state. The function context (this) is set to the droppable element. This function is passed the event instance and an object that contains information about the operation with the following properties:

  • draggable—The draggable instance
  • droppable—The droppable instance
  • element—The draggable element
  • helper—The draggable helper
  • options—The options passed to droppable()

deactivate

(Function) A callback function invoked when the droppable reverts to inactive state. This can be a transition from either active or armed state. The function context (this) is set to the droppable element, and this function is passed the same parameters as described for the activate callback.

over

(Function) A callback function invoked when the droppable makes a transition from active to armed state as a result of the draggable meeting the criteria defined by the tolerance option. The function context (this) is set to the droppable element, and this function is passed the same parameters as described for the activate callback.

out

(Function) A callback function invoked when the droppable makes a transition from armed to active state because of the draggable leaving the droppable as defined by the criteria specified by the tolerance option. The function context (this) is set to the droppable element, and this function is passed the same parameters as described for the activate callback.

drop

(Function) A callback function invoked when the draggable is dropped on the armed droppable. The function context (this) is set to the droppable element, and this function is passed the same parameters as described for the activate callback.

Extended options

 

activeClass

(String) A CSS class name applied to the droppable when it’s in active state.

hoverClass

(String) A CSS class name applied to the droppable when a suitable draggable is hovering over it—when the droppable is in armed state.

When we looked at creating draggables, we saw that we could create a perfectly serviceable draggable without specifying any options to the draggable() method—not so with droppable(). Although nothing bad will happen if we don’t specify any options when we make a call to droppable(), nothing good will happen either. A droppable created without an accept option does a pretty good impersonation of a brick.

By default, a droppable won’t consider any draggable suitable. And a droppable that we can’t drop anything on isn’t useful, is it? To create a droppable that we can drop something on, we need to specify an accept option that defines the draggables that the droppable should consider suitable.

Because nothing drives home concepts like playing with them yourself, we created a Droppables Lab. Bring up the file of chapter9/ui/lab.droppables.html, and you’ll see the display of figure 9.12.

Figure 9.12. The UI Droppables Lab lets us examine the effect of the various options on drag-and-drop operations.

Similar to the other labs, there’s a Control Panel that lets us specify the options to be applied to the droppable after clicking the Apply button. The Disable, Enable, and Reset buttons serve functions similar to their counterparts in the Draggables Lab.

In the Test Subjects Pane are six draggable elements and an element (which we’ll call the Drop Zone) that will become droppable after clicking the Apply button. Below the Drop Zone are grayed-out text elements that read Activate, Over, Out, Drop, and Deactivate. When a corresponding droppable callback (added to the droppable behind the scenes by the lab) is invoked, the appropriate text element, which we’ll refer to as a callback indicator, is momentarily highlighted to indicate that the callback has fired.

Let’s dig in and get the skinny on droppables using this lab.

Exercise 1— In this exercise, we’re going to begin familiarizing ourselves with the Accept option, which is what tells the droppable what constitutes a suitable (or acceptable) draggable. Although this option can be set to any jQuery selector (or even a function that can programmatically make suitability determinations), for the purpose of the lab, we’ll concentrate on elements that possess particular class names. In particular, we can specify a selector that includes any of the class names flower, dog, motorcycle, and water by checking the appropriate check boxes of the Accept option controls.

The six draggable image elements on the left side of the Test Subject pane are each assigned one or two of these class names based on what appears in the image. For example, the upper-left draggable possesses the class names dog and flower (because both a dog and some flowers appear in the photo), whereas the lower-middle image is defined with the class names motorcycle and water (a Yamaha V-Star and the Colorado River, to be precise).

Before clicking Apply, try to drag and drop any of these elements on the Drop Zone. Aside from the dragging, not much happens. Carefully observe the callback indicators, and note how they don’t change. This should be no surprise because, at outset, no droppable even exists on the page.

Now, leaving all controls in their initial conditions (including all accept check boxes checked), click the Apply button. The executed command includes an accept option that specifies a selector that matches all four class names.

Once again, try to drag any of the images to the Drop Zone while observing the callback indicators. This time, you’ll see the Activate indicator briefly highlight, or throb, when you begin moving any of the images, indicating that the droppable has noticed that a drag operation has commenced and that the draggable is acceptable for dropping.

Drag the image over and out of the Drop Zone a number of times. The over and out callbacks are invoked (as shown by the corresponding indicators) at the appropriate times. Now, drop the image outside the confines of the Drop Zone, and watch the Deactivate indicator throb.

Finally, repeat the drag operation except, this time, drop the image on top of the Drop Zone. The Drop indicator throbs (indicating that the drop callback was invoked). Note, also, that the Drop Zone is wired to display the most recent image that was dropped upon it.

Exercise 2— Uncheck all of the accept check boxes, and click Apply. No matter which image you choose, no callback indicators throb, and nothing happens when you drop an image on the Drop Zone. Without a meaningful accept option, our Drop Zone has become a brick.

Exercise 3— Try checking at least one accept check box, say Flower, and note how only images with flowers in them (known to the page as such because the class name flower was defined for them) are construed to be acceptable items.

Try again with whatever combinations of acceptable class names you like until you’re comfortable with the concept of the accept option.

Exercise 4— Reset the controls, check the activeClass radio button green-Border, and click Apply. This supplies an activeClass option to the droppable that specifies a class name that defines (you guessed it) a green border.

Now, when you begin to drag an image that’s acceptable to the droppable (as defined by the accept option), the black border around the Drop Zone is replaced by a green border. If you have trouble getting this to work for you on your own pages, note that you need to be mindful of CSS precedence rules. When an activeClass class name is applied, it must be able to override the rule that assigns the default visual rendition that you wish to supplant. This is also true of hoverClass.

Exercise 5— Check the hoverClass radio button labeled RedBorder, and click Apply. When an acceptable image is dragged over the Drop Zone, the border changes from green (as a result of the activeClass setting) to red.

Experiment with these two option settings until you’re comfortable with the timing in the drag operation where each option triggers a class change.

Exercise 6— For this exercise, choose each of the various tolerance radio buttons, and note how the setting affects when the droppable makes the transition from active to armed state (as described by the definition of this option in table 9.3). This transition can easily be observed by setting the hoverClass option or when the Over callback indicator throbs.

Like their counterpart draggables, droppables can be destroyed, temporarily disabled, and then re-enabled. The methods to do so are as follow:


Command syntax: droppableDestroy

droppableDestroy()

Removes the ability to serve as a droppable from all elements in the wrapped set

Parameters

  • none

Returns

The wrapped set



Command syntax: droppableDisable

droppableDisable()

Suspends droppability of the wrapped droppable elements without removing the droppability information or options

Parameters

  • none

Returns

The wrapped set



Command syntax: droppableEnable

droppableEnable()

Restores droppability to any droppables in the matched set that had been disabled via droppableDisable()

Parameters

  • none

Returns

The wrapped set


Drag-and-drop is a useful interaction technique for many purposes. It’s frequently used to indicate association but may also be used to rearrange the order of elements. This latter use is common enough to warrant direct support by the UI Plugin. Let’s look into that.

Other mouse interaction methods

The remaining category of commands in the mouse interaction category of the UI Plugin are sortables, selectables and resizables. The methods in these categories leverage the drag-and-drop capability to allow elements to be reordered within a container and resized, respectively.

As with the UI Plugin commands we’ve examined so far, each of these operates by applying methods to a matched set and passing in an object hash that specifies the options. For complete details, please refer to http://docs.jquery.com/UI.

In addition to dynamic drag-and-drop and other mouse interaction operations, the UI Plugin also provides a number of widgets that we can use to extend the basic set of user interface elements that are natively provided by HTML.

9.4.2. UI widgets and visual effects

Although we’d love to go into great detail regarding the extensive set of user interface widgets that the UI Plugin provides, reality intervenes. In lieu of any deep discussion, we’ll at least give you a taste of what’s available, so you’ll know what to go look up in the online documentation.

The following lists the available widgets with short descriptions. Visit http://docs.jquery.com/ui for more details.

Accordion— A simple widget that creates expanding and contracting levels out of simple markup, such as lists or nested <div> elements.

Tabs— A widget for creating tabbed sets with a fairly interesting and potentially complicated set of options. Anchor elements are used to specify the tabs, and their href attributes are used to identify the tabbed sections (using page-internal hash references). This widget accounts for usage of the back button and can be configured to open a specific tab on page load.

Calendar— A widget that provides a dynamic date picker, which is associated with an input element. This widget is highly configurable and can appear on-page or within a dialog box.

Dialog— A modal dialog box widget with move and resize capability.

Slider— A control that creates a slider (similar to that available for desktop applications) that can be integrated into a form via hidden elements. The control can be oriented in various ways, and its minimum and maximum values are completely configurable.

Table— A sortable table widget that’s considered robust and fast.

In addition to these widgets, the following visual effects are provided:

Shadow— Generates a drop shadow for specified elements.

Magnifier— Causes the contents of elements to enlarge (magnify) upon mouse proximity.

With these UI elements at our disposal, we gain many options for creating great Rich Internet Applications. As they say, “But wait! There’s more!” The jQuery community is willing to share their enhancements to jQuery. Visit http://jquery.com/plugins for some insight into the many—and we do mean many—plugins that have been published by other jQuery users.

9.5. Summary

From the outset, jQuery’s creators designed it to provide an easy, but robust, plugin architecture. The idea was that the core jQuery download would stay small and limber, providing only those core features required by most web application authors and leaving the rest to plugins that could be included as needed. That strategy has served jQuery well as the community of its users has created and published a vast array of plugins that any user of jQuery can download and employ.

Taking a survey of some of the more often-used plugins, we saw a wide range of functionality that enhances the core jQuery feature set.

The Form Plugin provides wrapped methods that allow us to deal with form elements in a controlled fashion, even allowing us to instrument forms for easy submission through Ajax requests rather than the traditional full-page refresh.

Getting accurate (or even quick-and-dirty estimates) of the position and dimensions of DOM elements is provided by the Dimensions Plugin, which is essential when trying to accurately place elements on the page in relation to one another or to the page origin.

Another plugin that’s indispensable is the Live Query Plugin, which allows us to register event handlers for elements that don’t even exist yet. This seemingly non-causal ability is an enormous advantage for pages in which we expect DOM elements to be frequently created and destroyed over the lifetime of the page.

The UI Plugin, which we unfortunately weren’t able to fully explore, provides such essential user interface capabilities as drag-and-drop, sorting, and a handful of useful user interface widgets.

And that’s just the beginning. Drop in on http://jquery.com/plugins for a list of other available plugins. More and more get added all the time!

9.6. The end?

Hardly!

Even though we’ve presented the entire jQuery API within the confines of this book, it would have been impossible to show you all the many ways that this broad API can be used on your pages. The examples that we presented were chosen specifically to lead you down the path of discovering how you can use jQuery to solve the problems that you encounter on a day-to-day basis on your web application pages.

jQuery is a living project. Heck, it was quite a chore for your authors to keep up with the rapid developments in the library over the course of writing this book. The core library is constantly evolving into a more useful resource, and more and more plugins are appearing on practically a daily basis.

We urge you to keep track of the development in the jQuery community and sincerely hope that this book has been a great help in starting you on writing better Rich Internet Applications in less time and with less code than you might have ever believed possible.

We wish you health and happiness, and may all your bugs be easily solvable!

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

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