Note: The Dojo Quick Start Guide posts – while still relevant – are a bit dated. Please visit http://dojotoolkit.org/documentation/ for expert tutorials and API documentation to help you get up and running with Dojo.
Ajax is an acronym for “Asynchronous JavaScript and XML”, a technology employed to send and receive data on the fly. It can be used to update sections of a website from any number of remote sources, send data to the server and pass responses back and forth, all without ever refreshing the web page.
Having been versed on some essential Dojo methods already, now we’ll move on the the bread and butter of Ajax: the XMLHttpRequest (or XHR for short).
Dojo has several XHR methods available using common HTTP verbs: POST, GET, PUT, and DELETE. To prepare, we need to create a file with some text to load in when making our HTTP request.
Create a file named sample.txt in your js/ folder with sample text:
We used Ajax to put this text
in our page.
And modify the skeleton.html to have some basic markup and style:
<style type="text/css">
#container {
border:1px dotted #b7b7b7;
background:#ededed;
width:75px;
height:55px;
}
</style>
<div id="container" class="box">
<div id="content">
I am some Inner Content.
I am going to be replaced
</div>
</div>
dojo.Deferred
behind the scenes to handle callbacks. This is beyond the scope of a QuickStart, but extremely useful in practice. If you would like to learn more about callbacks and the various way to set them up, visit the Robust Promises with Dojo Deferred blog post or the <a href="http://dojotoolkit.org/api/dojo/Deferred.html">dojo.Deferred</a>
API pages.Getting data
The first stepping stone is dojo.xhrGet
, which will return the contents of a GET call on a URL. The XHR methods share a lot of common parameters. Most important are the url:
(our destination) and handleAs:
(how we handle what is coming back). When the data arrives, it will be passed the the load:
function we define:
var init = function(){
var contentNode = dojo.byId("content");
dojo.xhrGet({
url: "js/sample.txt",
handleAs: "text",
load: function(data,args){
// fade out the node we're modifying
dojo.fadeOut({
node: contentNode,
onEnd: function(){
// set the data, fade it back in
contentNode.innerHTML = data;
dojo.fadeIn({ node: contentNode }).play();
}
}).play();
},
// if any error occurs, it goes here:
error: function(error,args){
console.warn("error!",error);
}
});
};
dojo.ready(init);
You will notice we’ve combined techniques above. The content will fade out, be replaced by the received data, and fade back in using methods we’ve learned to this point. It was almost too easy.
A single handle
argument can be used instead of load and error, handling both success and failure cases in a common function:
var init = function(){
dojo.xhrGet({
url: "js/sample.txt",
handleAs: "text",
handle: function(data,args){
if(typeof data == "error"){
console.warn("error!");
console.log(args);
}else{
// the fade can be plugged in here, too
dojo.byId("content").innerHTML = data;
}
}
});
};
dojo.ready(init);
XHR has limitations. The big one being that url
is not cross-domain. You cannot submit the request outside of the current host (e.g. to url:"http://google.com"
). It is a known limitation and a common mistake when getting excited about Ajax. Dojo provides alternatives like dojo.io.iframe
and dojo.io.script
for more advanced usage.
A full list of XHR parameters is available at the Dojo XHR API page. We are only going to skim the surface here.
Sending Data
All Dojo XHR methods are bi-directional. The only difference is the method. Using dojo.xhrPost
, we use the POST method, embedding the data in the request (as opposed to the query string as with dojo.xhrGet
). The data can be set directly as an object passed to the content parameter:
dojo.ready(function(){
dojo.xhrPost({
url:"submit.html",
content: {
"key":"value",
"foo":42,
"bar": {
"baz" :"value"
}
},
load: function(data,ioargs){
console.log(data);
}
});
});
Or more commonly, conveniently copied and converted from a form
element! First, make a simple unobtrusive form in the skeleton.html:
<form id="mainForm" action="ajax-submit.php" method="post">
<label for="firstName">Name: </label>
<input type="text" name="firstName" value="Enter Name" />
</form>
Then, add in some JavaScript to submit the form by using dojo.connect
to listen to the onSubmit
event, and post the contents of the form to an alternate URL:
// submit the form
var formSubmit = function(e){
// prevent the form from actually submitting
e.preventDefault();
// submit the form in the background
dojo.xhrPost({
url: "alternate-submit.php",
form: "mainForm",
handleAs: "text",
handle: function(data,args){
if(typeof data == "error"){
console.warn("error!",args);
}else{
// show our response
console.log(data);
}
}
});
};
dojo.ready(function(){
var theForm = dojo.byId("mainForm");
// another dojo.connect syntax: call a function directly
dojo.connect(theForm,"onsubmit","formSubmit");
});
e.preventDefault()
being used again. The default nature of a form being submitted to to visit a new page, and we want to prevent that from happening.An example alternate-submit.php
would look like:
<?php
print "DATA RECEIVED:";
print "<ul>";
foreach($_REQUEST as $key => $var){
print "<li>".$key." = ".$var."</li>";
}
print "</ul>";
?>
Object Data
Getting text back from the server is nice, but the really great stuff comes when you start passing JavaScript objects around. Using a different handleAs:
attribute, we can alter how Dojo handles the response data. Make a new file named simple-object.json
to load:
{
foo: "bar",
name: "SitePen",
aFunction: function(){
alert("internal function run");
},
nested: {
sub: "element",
another: "subelement"
}
}
We’ll target our xhrPost url:
at the new file, and use handleAs: "json"
. This automatically converts the response data into a JSON object we can conveniently use:
var postData = function(){
dojo.xhrPost({
url: "js/simple-object.json",
handleAs: "json",
load: function(data,ioargs){
// success: set heading, run function
dojo.byId("testHeading").innerHTML += " by: "+data.name;
if(data.aFunction && data.aFunction()){
// we just ran data.aFunction(). should alert() ...
}
}
});
};
dojo.ready(postData);
dojo.xhr
exists as a wrapper for each of the method specific calls. If you use dojo.xhr
, add another property, method
, with the value in uppercase, e.g. GET, PUT, POST, or DELETE.This allows us to send literally any kind of data back and forth across the wire, without ever interrupting the user experience.