JavaScript & AJAX
Modern web applications often feature specialized effects
and attractive user interfaces accomplished by JavaScript code.
Writing in JavaScript directly is tedious and error-prone;
a significant problem is dealing with browser differences.
Generally it it preferable to write JavaScript using a
client-side toolkit, because it has the abilities to:
- add and replace functionality to JavaScript
- hide browser differences and quirks
- optimize the usage of JavaScript code
As can be expected, there are quite a few such toolkits, for example:
Dojo,
Prototype,
MochiKit,
Google Web Toolkit,
AJILE,
Echo,
jQuery,
MooTools,
qooxdoo,
Rico,
Scriptaculous,
YUI.
AJAX Programming
AJAX is an acronym for
Asynchronous
Javascript
And
Xml.
The most important point about AJAX is that it uses
JavaScript to
make
Asynchronous
server-side activations without doing browser
reload.
An asynchronous server-side activation proceeds while the browser
remains available for normal event handling. AJAX programmin gallows web
applications to behave more like standard graphical user interface applications.
When information is sent back from the server side activation, it
is the job of the JavaScript handler to decide what to do with it.
Often it is displayed as a whole within an element.
There are many circumstances in which it is useful to send back
structured information, whose parts can be identified and used.
The
X in AJAX signifies that XML information can be sent back
and parsed in JavaScript in order to extract the components.
In reality it is much more common and simpler to retrieve and process
information in JSON (JavaScript Object Notation) format.
JavaScript Debugging
JavaScript used in any setting is difficult to debug. In many cases when
something is wrong, nothing at all happens, i.e., there is no feedback
whatsoever about what is missing or how to fix it.
Firefox, for example, provides an
Error Console to show errors,
but the "mistake" may not technically be a JavaScript error.
One common debugging need is to ensure that some portion of code
is actually being executed when you think it should be executed.
A simplistic technique is to insert an
alert statement:
to ensure that execution does in fact reach this point in the code.
The problem is that the
alert blocks the browser and
can only display values of simple scalar variables.
A significant improvement is to be able to use a debugging
Console which shows you the AJAX calls made,
reports errors, and is able to log messages without blocking
the browser. A good choice is the
Firebug
tool available in Firefox and Chrome.
With this, you can insert logging statements like this into your code:
The "
if (window.console)" means "if the browser has a console."
It is necessary to avoid errors if the browser used does not have a
console installed.
Additionally Firebug provides an
HTML view which displays
JavaScript-generated code not visible generated which is
not viewable as source code.
JavaScript Programming
JavaScript programming bears strong resemblance to Java programming.
One strong difference is that JavaScript programming is completely focused
on controlling the browser behavior according to the heirarchical
Document Object Model (DOM). The top of the DOM
window object,
representing the entire browser. The sub-objects of
window are these:
- window.document = document (referring to the HTML document
contents),
- window.navigator = navigator (information about the browser type, version, etc),
- window.location = location (information about the URL being accessed),
- window.history = history (access to previous pages),
- window.status = status (the status bar at bottom of browser),
- window.frames[] = frames[] (access to frames in a frame-based layout).
JavaScript, like Java, also frequently uses the special variable
this to identify the object itself.
JSON
Another significant difference with Java is the usage of data structure literals
which are expressed in JSON (
Java
Script
Object
Notation).
The JSON
map uses this notation
var obj = { "x": 222, "y": "hello" }
We can omit the quotes around the keys in most circumstances, i.e., this is OK:
var obj = { x: 222, y: "hello" }
A map behaves in every way like a JavaScript object, meaning that
key access is available both in
array-style as
obj['x'] and
object-member-style as
obj.x.
JSON notation embraces both (indexed) list and map data structures. The
JavaScript
Array is effectively a list, and can be created as a literal
using the bracket
[ ] syntax.
Here are some other examples:
var a = [ 12, "hello", 15 ] (an array)
var b = { z: [ 22, 33 ] } (an object with array value)
var c = [ {x: 12, y: "aa"}, {x: 17, y: "bb"} ] (an array of objects)
From these we can use the following expressions:
a[2] (=15), b.z[1] (=33), c[0].x (=12), c[1][y] (="bb")
Beware of using a terminal comma in JSON maps and lists:
{ x: 11, y: 12, } and [ 12, "hello", 15, ]
Acceptance of this terminal comma is, unfortunately, browser-dependent (IE will typically choke on it).
Installing jQuery
The jQuery home page is:
Running jQuery requires only one JavaScript file.
The version used in this document is
1.6.4 and the file used is this (which can be downloaded from
the link):
This file is in the
minified form,
as identified by the presence of the "
.min"
in the file name. The jquery file is also available in normal form,
jquery-1.6.4.js.
The minified form, compared to the normal form, has all possible
whitespace characters removed from it making it unreadable,
but making it download faster.
Furthermore, web servers can compress and transmit this minified file in
a format which modern browsers can accept. Here is the comparison:
|
full (v.1.6.4) jQuery file:
|
KB
|
|
minified (v.1.6.4) jQuery file:
|
KB
|
|
compressed, minified (v.1.6.4) jQuery file:
|
KB
|
In general, you would make this file available from your site, perhaps in a dedicated script
directory named
js. Loading the jQuery file requires the script tag like this:
An alternative is to use the file hosted on Google using this:
jQuery Plugins
A jQuery
plugin is simply a jQuery-based JavaScript file which extends
the functionality of jQuery by adding other general features. Often such plugins
also require additional support CSS files.
Once loaded, the plugin functionality is activated by one
or more lines of additional jQuery code statements
which activate functions defined in the plugin.
jQuery Preliminaries
The jQuery package has the advantage of being usable without having to
modify the HTML and so jQuery JavaScript code can be introduced
through script sections and external script files and avoid
the insertion of JavaScript code into the element handler attributes
(
onclick,
onsubmit,
onchange, etc).
For this reason,
the jQuery-based JavaScript files can often be loaded just before the
end of the body tag, making the script loading concurrent with the
browser's application of style rules to the document, and thereby reducing
the latency of the web page loading.
jQuery employs these special JavaScript variables and makes them into
jQuery entities using the
$(..) wrapper. In particular, the
heart of jQuery code uses the structure:
What is being expressed is that, when the document is ready, call the function
to effect certain actions within. JavaScript and client-side toolkits make
heavy usage of
anonymous functions which do something when an event
takes place.
The "
$" used is actually the special
jQuery object from which everything else is based.
This seems odd, but
$ is actually a legal identifier character in JavaScript, and thus
$ by itself is a legal identifier, along with
$x,
x$,
$x$y, etc.
Php, of course, also uses "
$", but in a very different way.
In general JavaScript variables usually stick to letters, digits and underscores.
When jQuery is loaded,
$ is synonymous
with the variable
jQuery, and so we could just as well use the following,
although, as we'll that "
$" is used frequently and so
is a great notational convenience.
The jQuery activation region is usually written in this compact code style:
It may look a bit too compact, but the crunched syntax "
})"
actually works well with many JavaScript source code formatters and
helps to keep the indentation levels lower.
The activation region structure syntax can
be further simplified as follows, although I avoid doing so:
Events
JavaScript event attribute names all start with "
on":
onready, onclick, onsubmit, onchange, ...
jQuery simply removes the
on prefix, and thus we get
$(document).ready( function() { ... } )
which is equivalent in pure JavaScript to:
document.onready = function() { ... }
Typical jQuery code assigns event handlers to elements within the document
like this:
$(document).ready(function() {
$(ELEMENT_IDENTIFIER).JQUERY_EVENT(function() {
// code to handle the event on element(s) specified by identifier
});
});
In some cases, we can simplify the presentation or reuse the event handler
by using a
named function. The function definition can occur after the
event binding because it is not called at the time it is specified in the event
handler. Furthermore, the definition is outside the activation region.
$(document).ready(function() {
$(ELEMENT_IDENTIFIER).JQUERY_EVENT(myHandler);
});
function myHandler() {
// code to handle the event on element(s) specified by identifier
}
Selecting elements by CSS-style expressions
To use jQuery in its intended manner without the JavaScript event handler
attributes, the HTML code must identify that key elements in the same
manner that would be done in order to apply style rules to the elements.
The most basic identifying attribute is, of course, the
id attribute,
but any element or group of elements which can "selected" by a style rule,
can be acted upon by jQuery code.
An element's
id attribute is commonly used in JavaScript
in conjunction with the expression:
var elt = document.getElementById("elt_id");
The jQuery equivalent is the expression:
The "
#elt_id" is actually a perfect choice for the designator because it
exactly matches CSS syntax used to identify the element.
jQuery makes CSS-style element identification a theme for its usage.
For example, using the expression
$(".some_class")
we can effect changes to
all elements in the document which define:
class="some_class"
As you would expect, these expressions identify the elements you would expect:
$("h3") all h3 elements within the document
$("ol.foo li") all li elements within an <ol class='foo'>...</ol> block
Handling an onclick event
A very common situation is to activate some JavaScript code when the user clicks
a button or hyperlink. The way jQuery expresses this is by the code:
The JavaScript
onclick event is turned into the jQuery click
function. As is done with "onload", the argument passed to the click function
is a function which will be executed when the
onclick event happens.
In the case of hyperlink clicking or form activation through submit buttons,
jQuery usually wants to "take control" and so we must prevent the default behavior.
This is done very easily by returning a
false value from the function:
Static vs Dynamic Event Binding
The call
represent a
static binding, or association, of the EVENT handler
function to the the element(s) identified by the JQUERY_SELECTOR in the
sense that the association is set when the HTML content is loaded into the
browser.
An equivalent way to express this association is as follows, using the
jQuery
bind function:
However, if the HTML content is
generated from JavaScript
execution, this binding is no longer valid. A stronger, dynamic, binding
needs to be established
using the jQuery
live function like this:
It is slightly more costly, because it must be re-checked after each
JavaScript modification to the DOM.
Common jQuery operations
jQuery has functions corresponding to all attribute settings in JavaScript.
The advantage is that they are easier to use and more consistent than the
Javascript equivalents. For example:
$( ... ).html(...) // corresponds to ".innerHTML"
$( ... ).val(...) // corresponds to ".value"
$( ... ).css(...); // corresponds to ".style" usage
$( ... ).attr(...); // corresponds to access of any attribute
html and val functions
The
html and
val functions take one or no arguments with this prescription:
-
when either of these functions are used without an argument,
the current content is returned:
-
when used with an argument, the content
is set by the argument like this:
The "
html" function
is used for most block elements with start and end tag pairs: paragraph,
header, table cell (
td,
th),
span,
div,
li, etc.
The "
val" function applies to all form
elements including those which use the
value attribute
(textfield/password fields, checkboxes, radio buttons and selection lists)
as well as
the content of
textareas, even though textarea uses start and end tag pair.
css and attr functions
The
css and
attr functions are used with one or two arguments.
To set, for example, the
background-color property of an element to
red,
we would do this in pure JavaScript:
document.getElementById("my_elt").style.backgroundColor = "red"
The "
backgroundColor" JavaScript property name
is an adaptation of
the equivalent
background-color style property. The transformation is
necessary to avoid the misinterpretation of "
-" as an operator.
In contrast, the jQuery equivalent expresses a more
direct usage of CSS properties.
We can use a JSON map to provide multiple style property settings within
a single
css call, e.g.:
The
attr function can be used to get/set
any element attribute whatsoever. For example, to disable an element, we would use this:
Used with one argument we could read the current attribute value:
Other jQuery functions
jQuery has many, many convenience functions which control the behavior of elements
in complex ways, many through controlled animation effects. For example, these:
show/hide (make elements appear/disappear)
toggle (alternatively show/hide)
animate (change CSS properties in a timed manner)
fadeIn/fadeOut (make elements appear/disappear through animated fading)
addClass/removeClass (add/remove a class name to an element)
If you are interested, take a look at the possibilities at
http://api.jquery.com/category/effects/.
Iteration over elements
jQuery provides the
each operator which permits iteration over any
structure with multiple elements, applying a function to each element.
For example, it can be used to iterate over a JSON array:
This code employs the idea of turning the JavaScript element,
some_array into a jQuery object,
$(some_array); it is a similar process used in other
cases such as the jQuery objects
$(document) and
$(this).
We can also iterate over multiple elements identified through CSS, e.g.,
given a list of numbers:
we could compute the sum as follows:
jQuery AJAX
jQuery relies on the general
$.ajax method:
$.ajax( parameter_map )
The entire set of
ajax map keys
in the jQuery docs,
but these are the most common values:
- url: (string) the server-side URL to call
- type: the query method "get" or "post" (default is "get")
- data: parameter/value JSON map
- success: function to handle successful activation with
data being sent from server
- dataType: how to interpret transmitted server data: "html" (default), "json", "xml", etc.
- error: function to handle errors
- async: (boolean) specifies whether the activation
should be asynchronous (default is true)
The key elements are these:
The
$.ajax activation initiates a server-side
call to the
url, sending parameters by what is specified in
the
parameter-map. When the server-side activation is
complete, the output generated by the url appears as the parameter
data
in the
success function, and we can use this
data
to change the content of the webpage through JavaScript code.
Convenience functions
The methods
$.get (for GET activations) and
$.post (for POST activations) are simplifications of the
$.ajax method.
For example, the call
$.get( url, parameter-map, function(data){ ... } );
is actually this:
$.ajax({
type: "get",
data: parameter-map,
success: function(data){ ... }
});
Both
$.get
and
$.post
accept up to 4 parameters:
$.get( URL, parameter-map, success-function, dataType);
Unnecessary arguments can be dropped or replaced by
null,
for example, if there are no parameter:
$.get( "some-url", function(data){ /* do something */ })
One very common usage is to have the server pass back structured JavaScript
information as a JSON object. In order to recognize this
retrieved data, we could use this type of call:
$.get(URL,params,function(data){/* data is JavaScript*/}, "json")
Again, jQuery provides a convenience function
$.getJSON which
automatically generates an equavlent to the previous statement more
simply:
$.getJSON(
URL,
params,
function(data) { /* treat data a JavaScript variable */ }
)
jQuery Form Plugin
The jQuery Form plugin which provides convience methods for generating
AJAX form activations through jQuery. Its home page is
found at
http://malsup.com/jquery/form.
The jQuery form plugin offers several convenience functions for AJAX form submission.
This plugin is loaded by
one JavaScript file (assuming version 3.36.0):
jquery.form-3.36.0.min.js
after the main jQuery file has been loaded. To understand what the form
plugin functions
provide, let us imagine the submission of a form
We could do an AJAX submission of this form as follows:
The jQuery
serialize function captures the form's
named parameters with their values as a parameter map. As
a convenience, the jquery form plugin simplifies this by automatically
capturing the url, data and type values from the form. We can replace
this call by the following:
Used in this way, the single parameter is the value of the
success
function. If we want the return data to be JSON type, then we must rewrite
as follows:
A final step is to set up so that the form is submitted this way
when it is submitted. We could do so explicitly as follows:
However, the form plugin gives a simpler way to do so:
Once again, the single function parameter is the success function.
The JSON datatype would reflect change similar to above: