Set - 3

Question 1 :

Some of the Google examples you cite don't use XML at all. Do I have to use XML and/or XSLT in an Ajax application?

Answer :

No. XML is the most fully-developed means of getting data in and out of an Ajax client, but there's no reason you couldn't accomplish the same effects using a technology like JavaScript Object Notation or any similar means of structuring data for interchange.


Question 2 :

Are Ajax applications easier to develop than traditional web applications?

Answer :

Not necessarily. Ajax applications inevitably involve running complex JavaScript code on the client. Making that complex code efficient and bug-free is not a task to be taken lightly, and better development tools and frameworks will be needed to help us meet that challenge.


Question 3 :

When do I use a synchronous versus a asynchronous request?

Answer :

Good question. They don't call it AJAX for nothing! A synchronous request would block in page event processing and I don't see many use cases where a synchronous request is preferable.


Question 4 :

How do I handle concurrent AJAX requests?

Answer :

With JavaScript you can have more than one AJAX request processing at a single time. In order to insure the proper post processing of code it is recommended that you use JavaScript Closures. The example below shows an XMLHttpRequest object abstracted by a JavaScript object called AJAXInteraction. As arguments you pass in the URL to call and the function to call when the processing is done.

function AJAXInteraction(url, callback) {
	var req = init();
	req.onreadystatechange = processRequest;
	function init() {
		if (window.XMLHttpRequest) {
			return new XMLHttpRequest();
		} else if (window.ActiveXObject) {
			return new ActiveXObject("Microsoft.XMLHTTP");
		}
}
function processRequest () {
	if (req.readyState == 4) {
		if (req.status == 200) {
			if (callback) callback(req.responseXML);
		}
	}
}
this.doGet = function() {
req.open("GET", url, true);
req.send(null);
}
this.doPost = function(body) {
    req.open("POST", url, true);
    req.setRequestHeader("Content-Type", "
    application/x-www-form-urlencoded");
    req.send(body);
    }
}
function makeRequest() {
    var ai = new AJAXInteraction("processme", 
    function() { alert("Doing Post Process");});
    ai.doGet();
}

The function makeRequest() in the example above creates an AJAXInteraction with a URL to of "processme" and an inline function that will show an alert dialog with the message "Doing Post Process". When ai.doGet() is called the AJAX interaction is initiated and when server-side component mapped to the URL "processme" returns a document which is passed to the callback function that was specified when the AJAXInteraction was created. 
Using this closures insures that the proper callback function associated with a specific AJAX interaction is called. Caution should still be taken when creating multiple closure objects in that make XmlHttpRequests as to there is a limited number of sockets that are used to make requests at any given time. Because there are limited number of requests that can be made concurrently. Internet Explorer for example only allows for two concurrent AJAX requests at any given time. Other browsers may allow more but it is generally between three and five requests. You may choose to use pool of AJAXInteraction objects. 
One thing to note when making multiple AJAX calls from the client is that the calls are not guaranteed to return in any given order. Having closures within the callback of a closure object can be used to ensure dependencies are processed correctly. 
There is a discussion titled Ajaxian Fire and Forget Pattern that is helpful. 


Question 5 :

What do I do on the server to interact with an AJAX client?

Answer :

The "Content-Type" header needs to be set to"text/xml". In servlets this may be done using the HttpServletResponse.setContentType()should be set to "text/xml" when the return type is XML. Many XMLHttpRequest implementations will result in an error if the "Content-Type" header is set The code below shows how to set the "Content-Type".

response.setContentType("text/xml");
response.getWriter().write("<response>invalid</response>");

You may also want to set whether or not to set the caches header for cases such as autocomplete where you may want to notify proxy servers/and browsers not to cache the results.

response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<response>invalid</response>");

Note to the developer: Internet Explorer will automatically use a cached result of any AJAX response from a HTTP GET if this header is not set which can make things difficult for a developer. During development mode you may want set this header. Where do I store state with an AJAX client

As with other browser based web applications you have a few options which include:
* On the client in cookies - The size is limited (generally around 4KB X 20 cookies per domain so a total of 80KB) and the content may not be secure unless encrypted which is difficult but not impossible using JavaScript.
* On the client in the page - This can be done securely but can be problematic and difficult to work with. See my blog entry on Storing State on the Client for more details on this topic.
* On the client file system - This can be done if the client grants access to the browser to write to the local file system. Depending on your uses cases this may be necessary but caution is advised.
* On the Server - This is closer to the traditional model where the client view is of the state on the server. Keeping the data in sync can be a bit problematic and thus we have a solution Refreshing Data on this. As more information processing and control moves to the client where state is stored will need to be re-evaluated.


Question 6 :

How do I submit a form or a part of a form without a page refresh?

Answer :

When creating a form make sure that the "form" element "onSubmit" attribute is set to a JavaScript function that returns false.

<form onSubmit="doAJAXSubmit();return false;" >
<input type="text" id="tf1" />
<input type="submit" id="submit1" value="Update"/>
</form>

You can also submit data by associating a function with a form button in a similar way.

<form onSubmit="doAJAXSubmit();return false;" >
<input type="text" id="tf1" />
<input type="button" id="button1" onClick="doAJAXSubmit()" value="Update"/>
</form>

Note that the form "onSubmit" attribute is still set. If the user hits the enter key in the text field the form will be submitted so you still need to handle that case.
When updating the page it is recommend you wait to make sure that the AJAX update of the form data was successful before updating the data in the page. Otherwise, the data may not properly update and the user may not know. I like to provide an informative message when doing a partial update and upon a successful AJAX interaction I will then update the page.


Question 7 :

How do I get the XMLHttpRequest object?

Answer :

Depending upon the browser...

if (window.ActiveXObject) { // Internet Explorer http_request = new ActiveXObject("Microsoft.XMLHTTP"); } else if...


Question 8 :

How do I handle the back and forward buttons?

Answer :

While you could go out and create a custom solution that tracks the current state on your application I recommend you leave this to the experts. Dojo addresses the navigation in a browser neutral way as can be seen in the JavaScript example below. 

function updateOnServer(oldId, oldValue, 
    itemId, itemValue) {
    var bindArgs = {
    url: "faces/ajax-dlabel-update",
    method: "post",
    content: {"component-id": itemId, "component-value":
    itemValue},
    mimetype: "text/xml",
    load: function(type, data) {
    processUpdateResponse(data);
    },
    backButton: function() {
    alert("old itemid was " + oldId);
    },
    forwardButton: function(){
    alert("forward we must go!");
    }
    };
    dojo.io.bind(bindArgs);
}

The example above will update a value on the server using dojo.io.bind() with a function as a property that is responsible for dealing with the browser back button event. As a developer you are capable of restoring the value to the oldValue or taking any other action that you see fit. The underlying details of how the how the browser button event are detected are hidden from the developer by Dojo. 
AJAX: How to Handle Bookmarks and Back Buttons details this problem and provides a JavaScript library Really Simple History framework (RSH) that focuses just on the back and forward issue.


Question 9 :

How do I send an image using AJAX?

Answer :

While it may appear that images are being sent when using AJAX with an application like Google Maps what is really happening is that the URLs of images are being send as the response of an AJAX request and those URLs are being set using DHTML. 
In this example an XML document is returned from an AJAX interaction and the category bar is populated.

<categories>
<category>
<cat-id>1</cat-id>
<name>Books</name>
<description>Fun to read</description>
<image-url>books_icon.gif</image-url>
</category>
<category>
<cat-id>2</cat-id>
<name>Electronics</name>
<description>Must have gadgets</description>
<image-url>electronics.gif</image-url>
</category>
</categories>

Notice that the image-url element contains the location of the URL for the image representing a category. The callback method of an AJAX interaction will parse the response XML document and call the addCategory function for each category included in the response XML document. The addCategory function looks up a table row element "categoryTable" in body of the page and adds a row to the element which contains the image.

<scrip type="text/javascript" >
function addCategory(id, name, imageSrc) {

var categoryTable = document.getElementById("categoryTable");
var row = document.createElement("tr");
var catCell = document.createElement("td");
var img = document.createElement("img");
img.src = ("images\\" + imageSrc);
var link = document.createElement("a");
link.className ="category";
link.appendChild(document.createTextNode(name));
link.setAttribute("onclick", "catalog?command=category&catid=" + id);
catCell.appendChild(img);
catCell.appendChild(link);
row.appendChild(catCell);
categoryTable.appendChild(row);
}
</script>
<table>
<tr>
<td width="300" bgoclor="lightGray">
<table id="categoryTable" border="0" cellpadding="0"></table>
</td>
<td id="body" width="100%">Body Here</td>
</tr>
</table>

Note that the source of the image is set to the image source. The image is loaded by a subsequent HTTP request for the image at the URL "images/books_icon.gif" or "images/electronic_icon.gif" that occurs when the img element is added to the categoryTable.


Question 10 :

Will HTML_AJAX integrate with other Javascript AJAX libraries such as scriptaculous ? How would this integration look like?

Answer :

HTML_AJAX doesn't have specific plans to integrate with other JavaScript libraries. Part of this is because external dependencies make for a more complicated installation process. It might make sense to offer some optional dependencies on a library like scriptaculous automatically using its visual effects for the loading box or something, but there isn't a lot to gain from making default visuals like that flashier since they are designed to be easily replaceable.

Most integration would take place in higher level components. Its unclear whether higher level components like that should be part of HTML_AJAX delivered through PEAR or if they should just be supported by HTML_AJAX and made available from http://htmlajax.org or some other site. If your interested in building widgets or components based on HTML_AJAX please let me know.

HTML_AJAX does however offer the ability to use its library loading mechanism with any JavaScript library. I use scriptaculous in conjunction with HTML_AJAX and I load both libraries through the server.

To do this you just need to register the library with your server and load add its flag to your include line.

$this->server->registerJSLibrary('scriptaculous',
array('prototype.js','scriptaculous.js','builder.js','effects.js','dragdrop.js','controls.js','slider.js'), '/pathto/scriptaculous/');
<script type="text/javascrpt" src="server.php?client=scriptaculous"></script>