Base provides a small suite of functions suitable for use in a
RESTful design that significantly simplifies the process of performing
routine AJAX operations. Each of these functions provides explicit
mechanisms that eliminate virtually all of the boilerplate you'd
normally find yourself writing. Table 4-1 summarizes the property values
for args
.
Table 4-1. Property values for args
Name | Type (Default) | Comment |
---|---|---|
|
| The base URL to direct the request. |
|
| Contains key/value
pairs that are encoded in the most appropriate way for the
particular transport being used. For example, they are
serialized and appended onto the query string as |
|
| The number of
milliseconds to wait for the response. If this time passes,
then the error callback is executed. Only valid when |
|
| The DOM node or id for a form that supplies the key/value pairs that are serialized and provide the query string for the request. (Each form value should have a name attribute that identifies it.) |
|
| If true, then a special
|
|
| Designates the type of
the response data that is passed into the |
|
| The load function will
be called on a successful response and should have the
signature |
|
| The error function will
be called in an error case and should have the signature
|
|
| A function that stands
in for both |
|
| Whether to perform a synchronous request. |
|
| Additional HTTP headers to include in the request. |
|
| Raw data to send in the
body of a POST request. Only valid for use with |
|
| Raw data to send in the
body of a PUT request. Only valid for use with |
The RESTful XHR functions offered by the toolkit follow; as of
Dojo version 1.1, each of these functions sets the X-Requested-With: XMLHttpRequest
header to
the server automatically. A discussion of the args
parameter follows.
Tip
All of the XHR functions return a special Object
called Deferred
, which you'll learn more about in
the next section. For now, just concentrate on the discussion at
hand.
dojo.xhrGet(/*Object*/args)
Performs an XHR GET request.
dojo.xhrPost(/*Object*/args)
Performs an XHR POST request.
dojo.rawXhrPost(/*Object*/args)
Performs an XHR POST request and allows you to provide the raw data that should be included as the body of the POST.
dojo.xhrPut(/*Object*/args)
Performs an XHR PUT request.
dojo.rawXhrPut(/*Object*/args)
Performs an XHR PUT request and allows you to provide the raw data that should be included as the body of the PUT.
dojo.xhrDelete(/*Object*/args)
Performs an XHR DELETE request.
dojo.xhr(/*String*/ method, /*Object*/ args, /*Boolean?*/ hasBody)
A general purpose XHR function that allows you to define any arbitrary HTTP method to perform asynchronsously.
Although most of the items in the table are pretty
straightforward, the arguments that are passed into the load
and error
functions bear mentioning. The first
parameter, response
, is what the
server returns, and the value for handleAs
specifies how the response should
be interpreted. Although the default value is "text"
, specifying "json"
, for example, results in the response
being cast into a JavaScript object so that the response
value may be treated as
such.
Tip
In the load
and error
functions, you should always return
the response
value. As you'll
learn later in this chapter, all of the various input/output calls
such as the XHR facilities return a type called a Deferred
, and returning responses so that
callbacks and error handlers can be chained together is an important
aspect of interacting with Deferred
s.
The second parameter, ioArgs
,
contains some information about the final arguments that were passed
to the server in making the request. Although you may not need to use
ioArgs
very frequently, you may
occasionally find it useful—especially in debugging situations. Table 4-2 describes the values you might
see in ioArgs
.
Table 4-2. Property values for ioArgs
Name | Type | Comment |
---|---|---|
|
| The original argument to the IO call. |
|
| The actual |
|
| The final URL used for the call; often different than the one provided because it is fitted with query parameters, etc. |
|
| Defined only for non-GET requests, this value provides the query string parameters that were passed with the request. |
|
| How the response should be interpreted. |
At an absolute minimum, the arguments for an XHR request
should include the URL to retrieve along with the load
function; however, it's usually a
very good idea to include an error handler, so
don't omit it unless there you're really sure you can't possibly
need it. Here's an example:
//...snip... dojo.addOnLoad(function( ) { dojo.xhrGet({ url : "someText.html", //the relative URL // Run this function if the request is successful load : function(response, ioArgs) { console.log("successful xhrGet", response, ioArgs); //Set some element's content... dojo.byId("foo").innerHTML= response; return response; //always return the response back }, // Run this function if the request is not successful error : function(response, ioArgs) { console.log("failed xhrGet", response, ioArgs); /* handle the error... */ return response; //always return the response back } }); }); //...snip...
You may not necessarily want plain text back; you may want to time out the request after some duration, and you might want to pass in some additional information a query string. Fortunately, life doesn't get any harder. Just add some parameters, like so:
dojo.xhrGet({ url : "someJSON.html", //Something like: {'bar':'baz'} handleAs : "json", //Convert to a JavaScript object timeout: 5000, //Call the error handler if nothing after 5 seconds content: {foo:'bar'}, //Append foo=bar to the query string // Run this function if the request is successful load : function(response, ioArgs) { console.log("successful xhrGet", request, ioArgs); console.log(response); //Our handleAs value tells Dojo to //convert the data to an object dojo.byId("foo").innerHTML= response.bar; //Display now updated to say 'baz' return response; //always return the response back }, // Run this function if the request is not successful error : function(response, ioArgs) { console.log("failed xhrGet"); return response; //always return the response back } });
Do note that not specifying a proper value for handleAs
can produce frustrating bugs that
may not be immediately apparent. For example, if you were to
mistakenly omit the handleAs
parameter, but try to access the response value as a JavaScript
object in your load function, you'd most certainly get a nasty error
that might lead you to look in a lot of other places before
realizing that you are trying to treat a String
as an Object
—which may not be immediately
obvious because logs may display the values nearly
identically.
Although applications tend to perform a lot of GET requests,
you are bound to come across a circumstance when you'll need to PUT,
POST, or DELETE something. The process is exactly the same with the
minor caveats that you'll need to include a putData
or postData
argument for rawXhrPut
and rawXhrPost
requests, respectively, as a
means of providing the data that should be sent to the server.
Here's an example of a rawXhrPost
:
dojo.rawXhrPost({ url : "/place/to/post/some/raw/data", postData : "{foo : 'bar'}", //a JSON literal handleAs : "json", load : function(response, ioArgs) { /* Something interesting happens here */ return response; }, error : function(response, ioArgs) { /* Better handle that error */ return response; } });
Dojo version 1.1 introduced a more general-purpose dojo.xhr
function with the following
signature:
dojo.xhr(/*String*/ method, /*Object*/ args, /*Boolean?*/ hasBody)
As it turns out, each of the XHR functions from this chapter
are actually wrappers around this function. For example, dojo.xhrGet
is really just the following
wrapper:
dojo.xhrGet = function(args) { return dojo.xhr("GET", args); //Always provide the method name in all caps! }
Although you'll generally want to use the shortcuts presented
in this section, the more general-purpose dojo.xhr
function can be useful for some
situations in which you need to programmatically configure XHR
requests or for times when a wrapper isn't available. For example,
to perform a HEAD request for which there isn't a wrapper, you could
do the following:
dojo.xhr("HEAD", { url : "/foo/bar/baz", load : function(response, ioArgs) { /*...*/}, error : function(response, ioArgs) { /*...*/} });
Chapter 2 introduced
hitch
, a function that can be
used to guarantee that functions are executed in context. One common
place to use hitch
is in
conjunction with XHR callback functions because the context of the
callback function is different from the context of the block that
executed the callback function. The following block of code
demonstrates the need for hitch
by illustrating a common pattern, which aliases this
to work around the issue of context
in the callback:
//Suppose you have the following addOnLoad block, which could actually be any
//JavaScript Object
dojo.addOnLoad(function( ) {
//foo is bound the context of this anonymous function
this.foo = "bar";
//alias "this" so that it can be referenced inside of the load callback...
var self=this;
dojo.xhrGet({
url : "./data",
load : function(response, ioArgs) {
//you must have aliased "this" to reference foo inside of here...
console.log(self.foo
, response);
},
error : function(response, ioArgs) {
console.log("error", response, ioArgs);
}
});
});
While it may not look very confusing for this short example,
it can get a bit messy to repeatedly alias this
to another value that can be
referenced. The next time you encounter the need to alias this
, consider the following pattern that
makes use of hitch
:
dojo.addOnLoad(function( ) {
//foo is in the context of this anonymous function
this.foo = "bar";
//hitch a callback function to the current context so that foo
//can be referenced
var callback = dojo.hitch
(this, function(response, ioArgs) {
console.log("foo (in context) is", this.foo);
//and you still have response and ioArgs at your disposal...
});
dojo.xhrGet({
url : "./data",
load : callback,
error : function(response, ioArgs) {
console.log("error", response, ioArgs);
}
});
});
And don't forget that hitch
accepts arguments, so you could just as easily have passed in some
parameters that would have been available in the callback, like
so:
dojo.addOnLoad(function( ) {
//foo is in the context of this anonymous function
this.foo = "bar";
//hitch a callback function to the current context so that foo can be
//referenced
var callback = dojo.hitch(
this,
function(extraParam1, extraParam2
, response, ioArgs) {
console.log("foo (in context) is", this.foo);
//and you still have response and ioArgs at your disposal...
},
"extra", "params"
);
dojo.xhrGet({
url : "./data",
load : callback,
error : function(response, ioArgs) {
console.log("error", response, ioArgs);
}
});
});
If you may have a variable number of extra parameters, you can
instead opt to use arguments, remembering that the final two values
will be response
and ioArgs
.
Get Dojo: The Definitive Guide now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.