The additional formatting provided by this example is shown in the following screenshot: You should be aware of the fact that if the formatItem property is changed, the result that is ad
Trang 1"Prototype", "Regular Expressions", "Strings",
"Scope", "Typeof", "Undefined", "Variables", "XHR"
];
//provide additional markup for each result
function customItem(data, i, max) {
//add the link
return data[0] + " (<a href='" + data[0] + "'.html' title='" + data[0] + "'>" + data[0] + "</a>)"
Never mind that clicking on the link will cause the suggestion to be added to the text field instead of the link being followed, as we could easily add an additional click handler for this event and move the browser to the new page manually Or, perhaps the links could be triggers for some kind of tooltip The example is about adding additional formatting in the form of new mark-up, and that is exactly what we've done
The formatItem property is useful as it allows us to specify an alternative format for the results presented in the suggestion menu The premise is similar to that of the
highlight function, although in the case of formatItem, a regular expression is not needed to achieve the custom formatting
The function we specify as the value of formatItem receives four arguments when it
is called It receives the result, the row (or number) of the result, the total number of results, and the search term that was typed into the <input> field
Trang 2The result, is the data (the word returned as a result), and the row corresponds to the number of the result What is meant by this is that the first result will have a row number of 1, the second result will have a row number of 2, etc The total and term
values should not need further explanation The additional formatting provided by this example is shown in the following screenshot:
You should be aware of the fact that if the formatItem property is changed, the result that is added to the text field having been selected will automatically assume the formatting returned by formatItem
This may not be the desired behavior as we may want just the result, not arbitrary data that we supply with formatItem, to appear in the text field The next screenshot shows our text field when an item in the previous example has been selected:
Trang 3Thankfully, the auto-complete API provides the formatResult property which allows us to change the format of the data that is added to the text field following
a selection This can be most useful when working with custom formatting
provided by formatItem Following on from the previous example, change
autocomplete9.html so that it appears thus:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/ TR/html4/strict.dtd">
<label>Search our JavaScript Reference:</label>
<input type="text" id="suggest">
<script type="text/javascript" src="jqueryui1.6rc2/
"AJAX", "Anonymous functions", "Array",
"Assignment", "Boolean", "BOM",
"Callback functions", "Closures", "Comparison",
"Conditionals", "Deep Copy", "Design Patterns",
"DOM", "Events", "Functions", "Global Variables",
"HTML Output", "Inheritance", "JSON", "Keywords",
"Logical Operators", "Loops", "Math", "Namespacing",
"Null", "Objects", "Operators", "Properties",
"Prototype", "Regular Expressions", "Strings",
"Scope", "Typeof", "Undefined", "Variables", "XHR"
];
//provide additional markup for each result
function customItem(data, i, max) {
//add the link
Trang 4return data[0] + "( <a href='" + data[0] + "'.html' title='" + data[0] + "'>" + data[0] + "</a> )"
}
//customize data added to text field
function customResult(data, i, max) {
Save this version as autocomplete10.html The function specified as the value of
formatResult receives the same arguments as formatItem To negate the custom formatting provided by the formatItem function, our formatResult function
returns only the actual result This removes the additional mark-up 'inherited' from the formatItem function
The <input> field will now receive only the selected result, exactly as it did before
we altered the formatting of the data within each <li> element in the suggestion menu, as shown in the following screenshot:
Trang 5This additional data isn't part of the initial search of the data source, so it will not influence the returned matches in any way It's similar in structure to the other
format properties that we've looked at so far and receives the same arguments
Change autocomplete10.html to the following:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/ TR/html4/strict.dtd">
<label>Search our JavaScript Reference:</label>
<input type="text" id="suggest">
<script type="text/javascript" src="jqueryui1.6rc2/
"AJAX", "Anonymous functions", "Array",
"Assignment", "Boolean", "BOM",
"Callback functions", "Closures", "Comparison",
"Conditionals", "Deep Copy", "Design Patterns",
"DOM", "Events", "Functions", "Global Variables",
"HTML Output", "Inheritance", "JSON", "Keywords",
"Logical Operators", "Loops", "Math", "Namespacing",
"Null", "Objects", "Operators", "Properties",
"Prototype", "Regular Expressions", "Strings",
"Scope", "Typeof", "Undefined", "Variables", "XHR"
];
//provide additional information to the selection that doesn't get searched
function customMatch(data, i, max) {
return data + " (result number " + i + ")";
}
//define config object
Trang 6We've been working with a flat data structure in our examples so far and have provided a simple array containing the data items to match search terms against
We can also use more complex objects within our data structure, with additional data supplied using arbitrary keys and values
The keys will still be available to the functions for advanced formatting that we have just looked at This will give us the ability to provide additional information alongside the matched results
Matching properties
There are several properties which are used to configure how matching occurs with the auto-complete search term and results The mustMatch property, for example, configures the auto-complete so that the text field may only contain results supplied
by the widget Let's look at a basic example Change the configuration object used with our auto-complete in autocomplete12.html to the following:
//create config object
var autocompOpts = {
Trang 7Save the change as autocomplete12.html When we run this file in our browser, we see that as we start typing in the <input> with a letter that is a match for one of the results in our data set, the widget behaves as it has done so far.
If we start typing a letter in the <input> that isn't a match for our data (like a z for example) and then type another letter, the value of the <input> is cleared as a result
of the mustMatch property
Now let's look at a property that allows us to match not only the start of results in our data set, but to find matches within the strings which make up the data Change the configuration object, used in the previous example, to this instead:
//create config object
var autocompOpts = {
data: suggestions,
matchContains: true
};
Save this variation as autocomplete13.html Again, the premise with this property
is simple When a letter is entered into the text field, not just the results that start with the match are returned, but all results containing the match are returned as well, as you can see in the following screenshot:
Trang 8Remote data
We have used local data in all our examples so far, which is perfect for smaller data sets The data will be cached once it has been loaded, and continue to be available to the text field while the page is open It's efficient and easy to code
However, when working with larger stores of data, it is more efficient to process the suggestions on the server and return only those suggestions that are required Auto-complete makes working with remote data just as easy as working with local data, provided you have the back-end code to support it
There are a series of properties that are used solely with remote data sets These properties include the following:
As we'll be working with remote data for the next few examples, we can use a
slightly larger dataset For this example, I've created a new MySQL database called
data with a new table inside it called countries
We'll be using the auto-complete widget to provide a list of countries of birth on what could be part of an account creation form The data source we'll use for this example contains 128 records, which is still small enough to run locally with great efficiency, but is much larger than what we have worked with so far
I usually use PHP where necessary because I'm somewhat used to and like its syntax That's not to say that it's the only back-end language that could be used, or indeed the most practical, or most suited to the task at hand Nevertheless, let's get started with the next example In a new file in your text editor, add the following page:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/ TR/html4/strict.dtd">
Trang 9<body>
<label>Please enter your country of birth:</label>
<input type="text" id="suggest">
<script type="text/javascript" src="jqueryui1.6rc2/
Save this file as autocomplete14.html Instead of using the data property to point
to a local data source, we instead use the url property to point to the URL from which the data can be obtained No additional configuration is required for this simple implementation, although we do, of course, need a backend
For reference, the backend that I used for this example consists of the database I already mentioned and the following PHP file:
$server = mysql_connect($host, $user, $password);
$connection = mysql_select_db($database, $server);
/* get querystring parameter */
$param = $_GET['q'];
/* protect against sql injection */
Trang 10mysql_real_escape_string($param, $server);
/* query the database */
$query = mysql_query("SELECT * FROM countries WHERE country LIKE '$param%'");
/* loop through and return matching entries */
We also included the limit request variable, which will be set to the same value as the configured max property This property has the value of 100 by default with local data sources, but is set to 10 by the widget when using a remote data source
The following screenshot shows the remote auto-complete in action It looks exactly
as it did before, but we know that our slightly larger data set is actually remote:
Trang 11Sending additional data to the server
The only remote configuration property not related to caching is the extraParams
property This can be used to send additional, arbitrary data to the server Using this property is easy All we need to do is provide a nested object literal as the value of the property Change the configuration object used with autocomplete14.html to the following:
//create config object
Caching
The remaining remote properties are all related to the caching services provided by auto-complete, and they can all be used together for optimal cache performance I mentioned earlier that a GET request is performed on every keystroke That's not quite the whole truth and is where the local cache comes in
Every time a keystroke is detected in the associated text field, the local cache is checked first for matching results, and then a GET request to the remote data source
is made if nothing in the local cache matches
Trang 12The cacheLength property simply tells the widget how many items, if any, should
be stored in the local cache Caching can be disabled completely by setting this property to 1
The matchCase property configures the widget exactly the way that it implies When this is set to true, the auto-complete widget becomes case sensitive, so the term a will not be a match for A.
Finally matchSubset, which by default is set to true, makes subsets of the items in the cache match, so when a second letter is typed into the input, only the subset of results from the cache will be shown
Auto-complete methods
Now that we've looked at the configurable properties supplied by the auto-complete API, let's move on to look at the methods it exposes The following table lists the methods available when working with auto-complete:
Method Usage
destroy Removes auto-complete functionality from the <input>
flushCache Empties the cache
result A function specified as the second argument to this method can be used
to handle the selection of a resultsearch Programmatically triggers the search event
setData Supplies a new configuration object as the second argument of this
method to update the configuration of the matched <input> element's auto-complete
Like each of the other widgets, auto-complete has a method for removing
auto-complete functionality programmatically This is, of course, the destroy
method that we have seen many times before When called, the <input> element will no longer be associated with the auto-complete engine, and typing into it will not invoke the suggestion menu
The search and result methods are closely linked The result method allows us to specify a callback function that is triggered when the search event fires This occurs either when a visitor selects a result from the suggestion menu, or when the search
method is used to invoke the search event programmatically
Trang 13Let's look at the result method in our next example Change autocomplete15.html
<label>Please enter your country of birth:</label>
<input type="text" id="suggest">
<script type="text/javascript" src="jqueryui1.6rc2/
Argentina: "Mari mari",
Australia: "G'day Mate"
//set handler for selection of a result
$("#suggest").autocomplete("result", function(event, data, formatted) {
(!$("#greeting")) ? null : $("#greeting").remove();
$("<p>").text("You selected: " + formatted + ", " +
greets[data]).insertAfter("#suggest");
Trang 14Finally, we add an inline handler for the result event, and use it to retrieve the appropriate greeting from our greets object It is then appended to the page
whenever a suggestion from the menu is selected (after removing any previous messages if they exist):
We looked at the local caching of back-end results that is handled by auto-complete and saw how this can be fine-tuned to suit an individual implementation Apart from configuring the cache, the auto-complete API also gives us the means to empty the cache at any given point by calling the flushCache method
Flushing the cache may be required during the execution of your application if there
is a change to the data set that the auto-complete is tied to at the backend, and hence the URL used to query it
Changing things like the URL that the widget gets its data from, or any of the other configuration properties, is made easy with the setData method This method updates the configuration options of the auto-complete instance and takes as its second argument the new configuration object
Trang 15Fun with auto-complete
For our last auto-complete example, we can create a simple email system front-end that features an auto-complete attached to an <textarea> that is used to enter the address(es) that the email will be sent to It can be connected to a back-end data source containing the visitor's email contacts The following screenshot shows the kind of result we're aiming for:
While we won't be using every property and method exposed by the API, we can certainly put a range of them to good use with this example to reinforce what we've learned over this the course of this chapter Start off with the following basic web page:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/ TR/html4/strict.dtd">
Trang 16Save what we have so far as mailAddress.html We're keeping the page
simple for our final auto-complete example, using only the elements necessary to illustrate things The first <textarea> will be the one that is associated with our auto-complete
We'll need some basic CSS also while trying to keep this as simple as possible Add the following rules to a new file:
#mailContainer { width:700px; margin:0 auto; }
input, textarea { display:block; width:700px; }
Save this as mailAddress.css in the styles folder Now let's move swiftly on
to the most important, and unquestionably the most fun part of the example, the JavaScript In the empty <script> element in mailAddress.html, add the
Trang 17//create arrays for data
//add mail address to selected name
function mailMatch(data, i, max) {
in the AJAX date picker earlier in the book, and will be an array where each item in the array is an object containing name and mail keys where the contact's name is the value of name and their email address is the value of mail
The data from the JSON object is used to populate two arrays The first array will consist of each of the name values from each item, and the mails array will contain the mail addresses Because every value in the database that is pulled has two properties, the items in each array will always be in sync, so names[1] will always match mails[1]
Trang 18We then add a custom function to format the data that is added to the <textarea> The auto-complete will use the local names array as the data source Therefore, each time a name is selected from the auto-complete suggestion menu, the matching email address is added.
After this, we create the configuration object used to make auto-complete do the things we want, such as adding support for multiple selections, and then initialize the widget as normal We obviously need a PHP file as well to get the data out of the database in order to pass it back to our JSONP callback Again, this is being provided
$server = mysql_connect($host, $user, $password);
$connection = mysql_select_db($database, $server);
//protect against sql injection
mysql_real_escape_string($param, $server);
//query the database
$query = mysql_query("SELECT * FROM contacts");
//start JSON object
//return JSON with GET for JSONP callback
$response = $_GET["jsoncallback"] $contacts;
echo $response;
Trang 19I understand that you may not have the setup to run this file, or have any interest
in learning or using PHP, and that's fine Partly, the reason for using dynamic data locally via JSON and a JSONP callback is that you can still use this example without having your own local web server To this end, I have placed a copy of this file on
my own web server To use it, simply change the URL in the getJSON method to
http://www.danwellman.co.uk/jqueryui/contacts.php
Summary
The auto-complete is a fantastic and very fresh addition to the jQuery UI library It's intelligent, attractive, and intuitive to use As we've seen with the other library components, it's also easy to use from a developer's perspective and flexible enough
to be tailored to many individual situations
Your visitors will love it because it makes arduous tasks, like the completion of forms, easier and quicker It also improves the appearance and overall functionality
of your site while lending an air of quiet professionalism
We saw that this component brings to the table an impressive number of
configurable properties that allows us to fine-tune the user-experience with high precision We can use advanced formatting and matching properties to control the data that is outputted and how matching is performed, customize the appearance
of the drop-down suggestion menu, and much more
We also looked at the methods exposed by this component, including the usual
destroy method for removing functionality We can also programmatically flush the local cache and provide a new configuration object
Unlike most of the other components we have seen so far, the auto-complete event model is method-based instead of property-based However, it is equally as effective
at allowing us to react to important events fired during an interaction
Trang 20Drag and Drop
So far in this book, we've covered the complete range of fully released interface widgets, as well as one still (at the time of writing) in its beta phase Over the next four chapters, we're going to shift our focus to the core interaction helpers These components of the library differ from those that we've already looked at in that they are not physical objects that exist on the page
Instead, they give an object a set of generic behaviors to suit common
implementational requirements You don't actually see them on the page, but the effects that they add to different elements, and how they cause them to behave, can easily be seen These are low-level components as opposed to the high-level widgets There are currently five different interaction helpers, each catering for a specific interaction
They help the elements used on your pages to be more engaging and interactive for your visitors, which adds value to your site and can help make your web
applications appear more professional They also help to blur the distinction
between the browser and the desktop as application platforms
In this chapter, we'll be covering two very closely related components— draggables and droppables The draggables API transforms any specified element into
something that your visitors can pick up with the mouse pointer and drag
around the page Methods are exposed which allow you to restrict the draggables movement, make it return to its starting point after being dropped, and much more.The droppables API allows you to define a region of the page, or a container of some kind, for people to drop the draggables on to in order to make something else happen For example, to define a choice that is made, or add a product to a shopping basket A rich set of events are fired by the droppable that lets us react to the most interesting moments of any drag interaction
Trang 21The full range of subjects we'll be covering in this chapter are:
How to make elements draggable
How to determine the new position of an element that has been draggedThe properties that are available for configuring draggable objects
How to make an element return to its starting point once the drag endsHow to use event callbacks at different points in an interaction
The role of a drag helper
Containing draggables
How to control draggability with the component's methods
Turning an element into a drop target
Defining accepted draggables
Working with droppable class names
Defining drop tolerance
Reacting to interactions between draggables and droppables
The deal with drag and droppables
We'll be devoting ourselves to these two components for the duration of this chapter because of how closely related they are Dragging and dropping, as behaviors, go hand-in-hand with each other Where one is found, the other is invariably close by It's all very well dragging an element around a web page, but if there's nowhere for that element to be dragged to, or on top of, then the whole exercise is pointless.You can use the draggable class completely independent of the droppable class as pure dragging, for the sake of dragging, can have its uses, such as with the dialog However, you can't use the droppable class with the draggable You don't need to make use of any of draggables methods of course, but using droppables without having anything to drop onto them is of no value
These two components aren't designed to be used beyond simple drag and drop scenarios (which in themselves are complex pieces of web mechanics) If you have a more advanced requirement, like reordering list-based elements for example, you'll need to turn to a more specialized class, like the sortables component that we'll be looking at in the next chapter