Figure 5-2. Results from Listing 5-2 viewed in Palm Pre, Android, and Opera Mini mobile browsers
AJAX in Mobile Browsers
AJAX is commonly used to create dynamic web pages by updating just one portion of the web document, without a complete page reload. This is done by a background process that asynchronously obtains additional data from the web server. A JavaScript-intensive web page with AJAX functionality is commonly referred to as a Rich Internet
Application (RIA), where the term “application” indicates that the page’s user interface and functionality are dynamic and driven using scripting logic rather than static markup tags.
AJAX is implemented in advanced mobile browsers and is especially common on smartphones. It has numerous user experience and network efficiency benefits on mobile devices. AJAX reduces bandwidth because only fragments of web documents are transmitted in a network request. It produces web applications that update more quickly than full document refreshes. But mobile browsers also have challenges with AJAX features. AJAX may cause increased processing and can drain battery life due to the additional network requests required to dynamically update web content on
frequently updating pages with significant background activity. Mobile Web developers must detect support for AJAX using a device database, and iteratively include web application functionality only for supported browsers. Developers must judiciously incorporate AJAX into a Mobile Web site to reap the benefits of dynamic content updates without incurring additional user download costs or impacting battery life.
Many mobile browsers support AJAX, making it a viable technology for smartphones and other mobile phones with advanced Internet functionality. Android, iPhone, Palm webOS, Internet Explorer Mobile, and Nokia Series 60 (third edition and later) browsers all natively support AJAX. Recent versions of Opera Mobile, Opera Mini, and Access NetFront provide AJAX functionality for smartphone and newer featurephone browsers.
However, JavaScript fragmentation makes testing AJAX on actual mobile devices and browsers (not emulators) a priority. Remember, “mobile AJAX” doesn’t exist. The
“mobile” component and major point of fragmentation is the JavaScript implementation in the mobile browser. AJAX is AJAX in any web browser that supports its prerequisite standards. But, the Mobile Web is a special environment in which AJAX features can be disrupted by network latency, disconnects, request timeouts, and bandwidth issues.
At minimum, mobile browsers providing AJAX functionality must support XHTML-MP 1.1 or later, or XHTML and either ECMAScript MP or JavaScript. The JavaScript engine must include the XMLHttpRequest object (or similar; later in this section you will meet a different object used in Microsoft mobile browsers), a special JavaScript object that performs the asynchronous web requests at the heart of AJAX. (An industry acronym for XMLHttpRequest is XHR.) Additionally, the JavaScript implementation must also include DOM methods and properties in JavaScript that modify the structure of a web
document, especially document.getElementById(), element.innerHTML, and less commonly, element.innerText.
The innerHTML property of an XHTML or XHTML-MP element allows setting and getting of the markup inside the element. In practice, setting this property reconstructs the child DOM elements of this markup element. This property is used to update parts of the markup document in response to an AJAX request. For example, consider a markup document that contains the following div element:
<div id=”article”>Hello, World</div>
The JavaScript below updates the child markup of the div element:
of a web document, saving network bandwidth and preventing unnecessary retransmission of static document features.
The innerText property of an XHTML or XHTML-MP element allows setting and getting of the text inside the element. Setting this property changes the element’s textual content and removes any child DOM elements. For example, consider a markup document that contains the following div element:
<div id=”article”>Hello, World</div>
The value of the innerText property for the article element is the string “Hello, World”, as illustrated in the example below.
// This expression evaluates to true.
(document.getElementById(‘article’).innerText == ‘Hello, World’)
The innerText property is generally available only in mobile browsers that implement the desktop dialect of JavaScript, and it is used less commonly in AJAX transactions than its innerHTML relative. Firefox supports this property as textContent instead of innerText.
After using a device database to ensure that the target mobile browser supports JavaScript and AJAX, the basic implementation steps to include AJAX in a Mobile Web document are:
1. Decide how AJAX should be used to dynamically update part of the web document. Use JavaScript to handle the event that initiates the AJAX transaction.
2. In JavaScript, create an instance of XMLHttpRequest, the AJAX object making asynchronous requests to a web server.
3. In JavaScript, handle XMLHttpRequest state changes to detect errors and capture the web response document. The web response is usually XML, JSON, or an XHTML-MP or XHTML fragment.
4. In JavaScript, use document.getElementById and element.innerHTML to update the dynamic portion of the document.
5. Review the implementation to make sure that AJAX transactions are not used too frequently. Overuse of background web requests can cause browser performance degradation and impact battery life.
Although AJAX originally stood for "Asynchronous JavaScript and XML", it is not very practical to use XML as the web server response format for the third step in AJAX transactions, because this approach requires the mobile browser to parse and interpret XML. Instead, use an XHTML-MP or XHTML document fragment or JSON in the web response for better performance on mobile devices. Potentially, web response document fragments might also be transcoded in a mobile network, but this is an uncommon occurrence. Transcoding is discussed further in Chapter 12.
The first step in an AJAX transaction is to decide how AJAX is used in a web application to dynamically update part of the document. In the example in Listing 5-5, excerpted in Listings 5-3 and 5-4, AJAX initiates when the user activates a tab by clicking. In your Mobile Web application, AJAX can be triggered by user events or a JavaScript timer (if the mobile browser supports desktop ECMAScript).
NOTE: When AJAX transactions are controlled by a JavaScript timer (for periodically updating news headlines and so forth), always notify the user about background updates (for example, by using a loading animation), and allow the user to control the timer and choose to disable updates. This courtesy allows the mobile subscriber to control the charges and battery consumption associated with network use.
The second step in an AJAX transaction creates an instance of XMLHttpRequest, the AJAX object making asynchronous requests to a web server. The JavaScript function in Listing 5-3 is a standard method for creating an XHR instance to use in AJAX. Some Microsoft browsers including Internet Explorer Mobile support AJAX via ActiveX objects instead of XMLHttpRequest. The getXHR() function attempts to create an XHR using JavaScript object names supported in all mobile and desktop browsers. The function returns the new XHR instance or null if no such object was created. Notice the use of try and catch blocks to detect object creation errors.
Listing 5-3. JavaScript Function to Obtain an XMLHttpRequest Instance
// Function to obtain an instance of XMLHttpRequest used in an AJAX request function getXHR() {
The third step in an AJAX transaction handles XMLHttpRequest state changes to detect errors and capture the web response document. Listing 5-4 is a JavaScript function that implements an asynchronous web request using AJAX. The updateContent() function
successfully completed the request.
Table 5-3. Possible Values of the readyState Property of XMLHttpRequest Symbolic Value Numeric Value Description
UNSENT 0 The XMLHttpRequest object has been
created. No web request has been sent.
OPENED 1
The open() method has been called. The web request has been created but not yet sent. The send() method can be used to submit the request.
HEADERS_RECEIVE D
2 The web request has been sent. All
HTTP response headers have been received.
LOADING 3 The web request has been sent. All
HTTP response headers have been received. The response body has started to be received.
DONE 4 The web request is completed or
terminated with an error.
In Listing 5-4, the anonymous event handler for the onreadystatechange event performs three actions. If the asynchronous web request is in progress, it displays an animated loading image inside the element whose ID is the second function parameter. If the AJAX request completes successfully, the body of the web response is used as the content of the element. If the AJAX request terminates with an error, a textual error message is displayed to the user in the element. The handler function returns true when the AJAX request completes or false if the XMLHttpRequest object could not be
instantiated.
Listing 5-4. JavaScript Function to Obtain an XMLHttpRequest Instance // Global variable that holds the XHR instance.
var req = null;
// Use AJAX to update the page content.
// Returns true if the AJAX request succeeded, or false otherwise.
function updateContent(url, id) { req = getXHR();
The fourth step in an AJAX transaction uses document.getElementById and
element.innerHTML to update the dynamic portion of the document. Listing 5-4 displays the use of these constructs to find the div element with ID content and update its child HTML to reflect the progress of the request or display the document fragment obtained asynchronously.
The fifth step in an AJAX transaction reviews the implementation to make sure that AJAX transactions are not used too frequently. In the case of the AJAX example in Listing 5-5, AJAX is initiated by a user event (clicking to activate a tab), not based on JavaScript timers. AJAX functionality is entirely controlled by the user. If the user does not click a tab, then no AJAX transactions are initiated. Since the non-AJAX implementation of this feature would entail reloading the entire web document when a tab is activated, adding AJAX reduces bandwidth consumption. Herein lies the AJAX network performance efficiency. Transmitting a web document fragment instead of an entire web document means fewer bits across the wire(less).
create dynamic tabs in a Mobile Web document in XHTML-MP. As stated earlier, this web document uses AJAX to dynamically load an XHTML-MP document fragment when the user clicks to activate a tab in the user interface. Listings 5-3 and 5-4 excerpt getXHR() and updateContent(), two JavaScript functions used in Listing 5-5. The handleOnClick() function in Listing 5-5 uses JavaScript to update the visual style of the active and inactive tabs, as in the non-AJAX version of this example in Listing 5-2. In addition, handleOnClick()initiates an AJAX request to update the contents of the div element with ID content with dynamic markup requested from a web server.
In this example, the web documents requested using AJAX are static fragments of XHTML-MP markup. Browse to http://learnto.mobi/books/bmwd/05/5–5–0.php to view one of the static fragments. The URL targets of AJAX requests can be static or dynamic markup fragments, JSON, or XML documents.
It is worth noting the structure of the tab links in Listing 5-5. Each link has both an href attribute value and an onclick event handler, as in the example below:
<a href="5–3-0-static.php" id="tab0" class="activeTab" onclick="return handleOnClick(0);">Fruit</a>
When the AJAX transaction completes successfully, the handleOnClick() function returns false, canceling the click event. AJAX controls the document updates and the href is not followed. But when the AJAX transaction fails (in this case, when the XMLHttpRequest object cannot be instantiated), the handleOnClick() function returns true and the href is followed, navigating the browser to a new web document. This pattern of providing both an onclick event handler that implements AJAX and an href URL to a fallback static markup document is used to gracefully degrade the user experience when AJAX is unavailable in the mobile browser.
In Listing 5-5, the getXHR() function is embedded in the web document for the sake of providing a standalone AJAX example. The function could also be included in an external JavaScript library to maximize code reuse.
Browse to http://learnto.mobi/books/bmwd/05/5–5.php to view Listing 5-5 in a mobile or desktop browser.
Listing 5-5. Dynamic Tabs using AJAX and JavaScript in an XHTML-MP 1.1 Document
<?
// Set the response content-type
header("Content-type: application/xhtml+xml");
header("Cache-control: no-transform");
// Write the XML declaration
echo '<?xml version="1.0" encoding="UTF-8"?>';
?>
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.1//EN"
"http://www.openmobilealliance.org/tech/DTD/xhtml-mobile11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=240,user-scalable=no" />
<title>Listing 5–5: AJAX Tabs</title>
<style type="text/css">
// Global variable that holds the XHR instance.
var req = null;
// Function to obtain an instance of XMLHttpRequest used in an AJAX request function getXHR() {
req.open('GET', url);
// This is the onClick event handler for the tab links // index - the zero-based index of the tab that was clicked function handleOnClick(index) {
// Construct the ID of the clicked tab var tabId = "tab" + index;
// Update the style of the active tab.
document.getElementById(tabId).setAttribute('class', 'activeTab');
// Update the styles of the inactive tabs. This could also be achieved in a for loop.
if (index != 0) {
document.getElementById("tab" + 0).setAttribute('class', 'tab');
}
if (index != 1) {
document.getElementById("tab" + 1).setAttribute('class', 'tab');
}
if (index != 2) {
document.getElementById("tab" + 2).setAttribute('class', 'tab');
}
// Use AJAX to update the "content" div.
// Construct the URL to use to retrieve the updated content
var url = "http://learnto.mobi/books/bmwd/05/5–5–" + index + ".php";
// If the AJAX request succeeded, do not follow the original link if (updateContent(url, "content")) {
return false;
}
// If we are here, then the AJAX transaction failed.
// Follow the link and load the static page.
return true;
}
</script>
<noscript><p>Sorry, no script support in this browser.</p></noscript>
</head>
<body>
<h1>AJAX Tabs</h1>
<div id="tabs">
<a href="5–5–0-static.php" id="tab0" class="activeTab" onclick="return handleOnClick(0);">Fruit</a><a href="5–5–1-static.php" id="tab1" class="tab"
onclick="return handleOnClick(1);">Veggies</a><a href="5–5–2-static.php" id="tab2"
class="tab" onclick="return handleOnClick(2);">Honey</a>
</div>
<div id="content">Click a name to to activate the tab.</div>
</body>
</html>
Figure 5-3 shows the Mobile Web document from Listing 5-5 as displayed in the Palm Pre, Android, and Opera Mini mobile browsers. Make sure to view Listing 5-5 in a mobile browser to observe the performance of AJAX transactions on actual mobile devices.
Click each tab to view the loading image during the AJAX request and the content of each dynamically loaded document fragment.
Figure 5-3. Viewing the results of Listing 5-5 in Palm Pre, Android and Opera Mini mobile browsers