Using JavaScript to Manipulate Elements from the navigation bar, you could take out the onclick handler and put the URL for the links page in the link. The onmouseover event handler calls persist(), which displays the menu. The <div> containing the menu also has two event handlers: onmouseout and onmouseover. The onmouseout handler calls hideSoon(), which waits 1 second and then hides the menu. The onmouseover handler calls persist(), which displays the menu. This ensures that the menu stays open as long as the mouse is over the menu. Finally, each of the links in the menu also has an onmouseover handler that calls persist() so that the menu stays open when the user moves his mouse over the links themselves. Now let's look at the JavaScript code. You've already seen most of this stuff; it has just been put together in a different way. The persist() function is in charge of positioning and displaying the menu. First, I grab two referencesone to the menu and the other to the menu button. Were there multiple menus, this function would take the IDs of the button and menu as parameters. Once I have the references I need, it's time to display the menu. I set the position property to absolute, just in case. Then I set the top and left properties of the menu based on the position of the button associated with the menu: menu.style.top = (button.offsetTop + button.offsetHeight) + 'px'; menu.style.left = (button.offsetLeft) + 'px'; The offsetTop, offsetLeft, and offsetHeight properties are available for any visual element on a page. I determine where to put the top of the menu by adding the height of the button to the top position of the menu. That places it immediately under the button. The left side of the menu should line up with the left side of the button, so I just used offsetLeft for the left position of the menu. The other functions are less interesting. The highlightAndPersist() function just changes the background color of the button and calls persist(). The unhighlight() function just changes the background color of the button back to what it was. The hide() function sets the visibility of the menu back to hidden. There's a bit more going on in hideSoon(). It uses the setTimeout() function to wait 1,000 milliseconds (one second) and then call the hide() function. This improves the usability of the page a bit by giving the user a chance to see the menu even if he mouses out of it by mistake. Continuing Your DHTML Education I encourage you to visit both the Microsoft and Netscape websites devoted to DHTML. Each offers an interesting perspective. The Microsoft website has a ton of great information for using HTML and DHTML with Internet Explorer: http://msdn.microsoft.com/workshop/author/dhtml/dhtml_node_entry.asp Netscape appears to be leading the cross-browser compatibility charge and has extensive articles and technical notes at http://devedge.netscape.com/. You might also find http:// www.mozilla.org/docs/dom/ interesting. Other sites that have useful information include the following: file:///G|/1/0672328860/ch15lev1sec4.html (8 von 9) [19.12.2006 13:49:47] Using JavaScript to Manipulate Elements ● WebReference Dynamic HTML Lab (http://www.Webreference.com/ dhtml/) Contains examples and code ranging from drag-and-drop DHTML to expandable menus and outlines ● Brainjar (http://www.brainjar.com) Offers a library of JavaScript functions for adding DHTML to web pages file:///G|/1/0672328860/ch15lev1sec4.html (9 von 9) [19.12.2006 13:49:47] Connecting to a Server with AJAX Connecting to a Server with AJAX The aspect that dynamic HTML adds to regular HTML is the capability to manipulate elements on a page without sending requests back to the server to reload the entire page. You can hide or display items or even change their contents using JavaScript, Cascading Style Sheets, and the DOM. Using a JavaScript feature called XmlHttpRequest, you can take dynamic HTML one step further by requesting data from the server and incorporating it on the page without reloading the entire page. The technique is commonly referred to as AJAX, which is short for Asynchronous JavaScript + XML, and was originally described that way in an article by Jesse James Garrett of Adaptive Path. So far, you've seen how JavaScript can be used to manipulate objects that are already present on a web page. With XmlHttpRequest, you can write JavaScript that actually makes a call back to the server, submitting and receiving data. Let's say you have a web page that displays baseball scores and you want the scores to be updated automatically to show the progress of the games. Ordinarily, you would automatically refresh the entire page every so often, or the user could reload the page using her browser to get the most recent scores. Using AJAX, you could add some JavaScript to the page that goes back to the server and gets the latest scores periodically, updating that information while leaving the rest of the page intact. This provides users with a more seamless experience and saves bandwidth on your server, as the only parts that are downloaded are those that actually change. Dynamic HTML took web programmers most of the way toward creating web applications that work like desktop applications, and AJAX closes that gap even further. How AJAX Works AJAX depends on XmlHttpRequest. It was originally added to Microsoft Internet Explorer 5 as an ActiveX object, and has since been added to other browsers as a built-in JavaScript object. XmlHttpRequest will submit a request to a web server where the enclosing page is stored and return the results so that they can be used within the web page that made the XmlHttpRequest request. For security reasons, XmlHttpRequest only allows connections back to the web server where the page making the request is stored. In other words, if the page containing the XmlHttpRequest call is http://www.example.com/ajax. html, the browser could only submit requests to www.example.com. Originally, XmlHttpRequest was intended to retrieve XML documents from the server, but in actuality it can retrieve any content as long as it's text. You can then incorporate the results into your page using the DHTML techniques you've already seen in this lesson. The first step in using XmlHttpRequest is creating the object. As I mentioned, Internet Explorer and other browsers handle XmlHttpRequest differently, so you have to use the capability detection features that I mentioned in the " Creating an Image Rollover" section in Lesson 13, "Using JavaScript in Your Pages," to properly create the object. This also enables you to avoid running into problems with browsers that don't support XmlHttpRequest at all. Here's the code: if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } else if (window.ActiveXObject) { request = new ActiveXObject("Microsoft.XMLHTTP"); } file:///G|/1/0672328860/ch15lev1sec5.html (1 von 8) [19.12.2006 13:49:48] Connecting to a Server with AJAX First I check to see whether the browser provides XmlHttpRequest as a property of the window object. If it does (as browsers other than Internet Explorer do), I use the new keyword to create a new XmlHttpRequest object. If it does not, I check to see whether the browser supports the ActiveXObject property of window. Only Internet Explorer provides that feature, so if that check returns true, I can create an XmlHttpRequest object using ActiveX. The XmlHttpRequest object, once created, works the same in all browsers that support it. Here's how you use it to retrieve information from the server: request.onreadystatechange = processReadyStateChange; request.open("POST", "remote.cgi", true); request.send("user=test"); I'll explain the first line last. The second line is used to specify the request method and URL for the connection. The first argument, "POST" in this example, is the request method to use. You can use "GET" or "POST" here, just as you can with the action attribute of the <form> element, as discussed in Lesson 10, "Designing Forms." The second argument is the URL. Since the request must go to the server where the page resides, you can just use a relative or absolute URL. There's no need to specify the server or protocol. In this case, the script would submit the request to remote.cgi in the same directory as the page containing this code. The final argument specifies whether the request should be asynchronous, and can be either TRue or false. You'll almost certainly want to use true here all the time. If you don't set the request to be asynchronous, the browser will wait for the request to complete before letting the user do anything. Once you've created the connection, you need to send data over the connection using the send() method. If you use the GET method, you can just use an empty string ("") here. If you use POST, you'll include the actual data to send with the request as the argument to the send() method. Once again, think about the request as a form submission. You can gather data from form elements on the page and pass it to send() to submit the form via XmlHttpRequest rather than submitting the form itself. The data passed to send() should be encoded using URL encoding, as discussed in Lesson 10. After the data is submitted, your script has to handle the response from the server. That's where the first line comes in. In order to deal with the response, you have to register a function to handle events associated with XmlHttpRequest. You'd think that you could just write some JavaScript to handle the results and put it in your script after the line that sends the data to the server, but that's not how XmlHttpRequest works. Remember that I mentioned that XmlHttpRequest can be used asynchronously. What that means is that once the script sends the request, your code can go on and do other things while the browser deals with handling the results of the request. The browser processes the response by generating events. If you want to do anything with the results, you have to register a function as the handler for those events. I discussed event handlers back in Lesson 12, and I showed how you can register a function to handle them by using attributes of elements using attributes such as onclick or onchange. For example, if you wanted to register a handler for an onclick event for a link, you could use this code: <a href="/" id="mylink" onclick="linkClicked()">My link</a> There's another way to register a handler as well, entirely within a script. If you wanted to use JavaScript to register the event handler for the link, which I helpfully gave the ID mylink, you could do it like this: document.getElementById("mylink").onclick = linkClicked; file:///G|/1/0672328860/ch15lev1sec5.html (2 von 8) [19.12.2006 13:49:48] Connecting to a Server with AJAX One thing to note is that I don't include the () after linkClicked in the JavaScript example. That's because I want to associate the function named linkClicked with that event. If I include the parentheses, the script will actually call the function and assign the results to the onclick property. I want the function itself in this case. OK, back to XmlHttpRequest. As I mentioned, the browser handles the response by generating events. I specified the handler for those events on this line: request.onreadystatechange = processReadyStateChange; That line says that onreadystatechange events for the XmlHttpRequest object should be passed to a function named processReadyStateChange. When a response is being processed, it goes through multiple states before it's finished. Those states are listed in Table 15.2. Table 15.2. XmlHttpRequest States State Description 0 The open() method has not been called. 1 The send() method has not been called. 2 The send() method has been called but the response headers have not been sent back. 3 Some response data has been received. 4 All of the response data has been received. As you can probably guess, the states progress from 0 to 4. The function you associate with onreadystatechange is called every time the state advances. Here's what such a function looks like: function onreadystatechange() { if (request.readyState == 4) { window.alert("Finished!"); } } This function examines the readyState property of the XmlHttpRequest object to see what the current state of the request is. This function will be called once for every state change, but it doesn't do anything until state 4 is reached and the request is finished. At that point, it just displays an alert. Most handlers will be written like this because the only state you care about is state 4. In addition to readyState, XmlHttpRequest has other properties, which are listed in Table 15.3. file:///G|/1/0672328860/ch15lev1sec5.html (3 von 8) [19.12.2006 13:49:48] Connecting to a Server with AJAX Table 15.3. XmlHttpRequest Properties Property Description onreadystatechange The function specified to handle state change events readyState The current ready state for the object responseText The response sent by the server status The HTTP status code of the response statusText The text message associated with the HTTP status Once you've reached readyState 4, you can access the data passed back from the server via the responseText property and deal with it as you wish. An AJAX Example Now that you understand how AJAX works, here's an actual page that applies these principles. In this example, I've created a page that allows you to update the current temperature by pressing a button. I use XmlHttpRequest to retrieve the current temperature, and use JavaScript to replace a <div> on the page with data from the server. Here's the source code for the page: Input <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" version="-//W3C//DTD XHTML 1.1//EN" xml:lang="en"> <head> <title>AJAX Example</title> <script language="JavaScript"> var request = false; function sendAjaxRequest(toUrl) { if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } else if (window.ActiveXObject) { request = new ActiveXObject("Microsoft.XMLHTTP"); } if (request) { request.onreadystatechange = processReadyStateChange; request.open('GET', toUrl, true); request.send(""); } } function updateTemperature(msg) { var contentDiv = document.getElementById("ajaxTarget"); contentDiv.innerHTML = msg; file:///G|/1/0672328860/ch15lev1sec5.html (4 von 8) [19.12.2006 13:49:48] Connecting to a Server with AJAX } function getLatestTemp() { sendAjaxRequest("temp.txt"); } function processReadyStateChange() { if (request.readyState == 4) { if (request.status == 200) { updateTemperature(request.responseText); } else { alert("An error occurred."); } } } </script> </head> <body> <p> Current temperature: <div id="ajaxTarget" style="font-size: x-large;">90 degrees</div> </p> <p> <button onclick="getLatestTemp()">Update Temperature</button> </p> </body> </html> The page appears in Figure 15.6. Output Figure 15.6. A page that uses AJAX to update the current temperature. file:///G|/1/0672328860/ch15lev1sec5.html (5 von 8) [19.12.2006 13:49:48] Connecting to a Server with AJAX As you can see, the HTML section of the page is relatively short. All I have is a paragraph containing a <div> that contains the current temperature and another paragraph with a button that's used to update the temperature. When the user clicks on the Update Temperature link, the function specified in the onclick handler getLatestTemp()is called. That function contains a single line of code: sendAjaxRequest("temp.txt"); This code just calls another function I wrote called sendAjaxRequest(). The argument is the URL for the content on the server. Ordinarily, the URL would point to a script that looks up the current temperature and transmits it back to the user. In this case, I have a text file on the server in the same directory as this page, and XmlHttpRequest is happy to retrieve it. The temp.txt file contains only the following text: 55 degrees The code in the sendAjaxRequest() function should look familiar, since I just explained how it works. I create a new XmlHttpRequest object, assign a handler to the onreadystatechange event, open the connection, and send the request data. One thing you might notice is that I declare the request variable at the top level of my script rather than within my function. That's so that the variable is visible to the handler function as well as to the function where it is assigned. I also test to make sure that my attempts to create the XmlHttpRequest object were successful prior to calling any of its methods. That way I won't produce errors in older browsers that don't support XmlHttpRequest. In this script, my event handling function does a lot more than the previous one. Here's the source: function processReadyStateChange() { file:///G|/1/0672328860/ch15lev1sec5.html (6 von 8) [19.12.2006 13:49:48] Connecting to a Server with AJAX if (request.readyState == 4) { if (request.status == 200) { updateTemperature(request.responseText); } else { alert("An error occurred."); } } } As in the preceding code, the script only cares about readyState 4. It ignores all of the state changes leading up to it. Once readyState 4 has been reached, it checks the status property of the XmlHttpRequest object. A status of 200 means that the request was successful and the script received the text it wants. If the status is anything else, an error message is displayed. If the request was successful then the script calls the updateTemperature function, passing in the response text as an argument. In this case, temp.txt contains only the temperature to be displayed. More involved scripts could produce complex data structures represented as XML that the page has to unpack, but in this example I just want to take the result and display it. That's what updateTemperature() is for: function updateTemperature(msg) { var contentDiv = document.getElementById("ajaxTarget"); contentDiv.innerHTML = msg; } The code uses the getElementById() function to obtain a reference to the <div> on the page. It then replaces its current contents with the response text using the innerHTML property. As I said before, a real-life example would be significantly more complex, but this example illustrates how AJAX is used in a simple case. Unlike the other examples you've seen in this book so far, you'd have to put both the HTML page and temp.txt file on a web server in order for the example to work. XmlHttpRequest relies on the HTTP protocol, and its security constraints require the target to be on the same server as the page making the call. In Lesson 20, "Understanding Server-Side Processing," you'll learn how to write the kinds of scripts that are used to produce dynamic results for AJAX calls, unlike the static text file I provided for this example. file:///G|/1/0672328860/ch15lev1sec5.html (7 von 8) [19.12.2006 13:49:48] Connecting to a Server with AJAX Be Careful with AJAX AJAX is relatively new, and isn't supported in older browsers. As with dynamic HTML, you should make sure that your site is usable by people who can't take advantage of any of the features you provide using AJAX. AJAX can also be used in such a way that it breaks well-established web browsing conventions, such as the Back button. You should use AJAX to supplement your site, and not to implement the entire thing. Your users will probably be used to the way that most other websites work, and using too much AJAX may confuse them. file:///G|/1/0672328860/ch15lev1sec5.html (8 von 8) [19.12.2006 13:49:48] . deal with it as you wish. An AJAX Example Now that you understand how AJAX works, here's an actual page that applies these principles. In this example, I've created a page that allows. Path. So far, you've seen how JavaScript can be used to manipulate objects that are already present on a web page. With XmlHttpRequest, you can write JavaScript that actually makes a call. is a paragraph containing a <div> that contains the current temperature and another paragraph with a button that's used to update the temperature. When the user clicks on the Update