Ajax Hacks: Tips & Tools for Creating Responsive Web Sites

Create cookies within the web application and send cookie values to a server without refreshing the page.

A cookie is a small piece of data that a web application can store on a user's machine. A web site can set one or more cookies using a Set-Cookie header in the server response. The number of cookies that a server can set and their individual sizes are restricted based on the standards used by the first browser makers, such as Netscape.

A web server may set no more than 20 cookies for one browser, and each cookie's size is limited to 4K. (Very few cookies reach that size.) If you want to view the cookies in your Firefox installation, go to PreferencesPrivacyCookiesView Cookies. Most browsers, including Firefox, allow the user to remove cookies.

If Google or Yahoo!, for instance, has set a cookie on your machine, that business's web applications will be able to read the cookie name and value the next time you go to its site. For example, Google may set a unique ID on your machine so that it can identify you and display your preferential news headlines when you visit the Google News site. The upcoming sections will explain how code sets the accessibility of the information the cookies store.

Bake Your Own Cookie

This hack allows a user to enter the name and value of a cookie. The application then uses this information to generate a new cookie. Figure 4-13 shows the interactions that take place in this hack between the browser and the server.

Figure 4-13. Creating, viewing, and posting cookie data

The simplest cookie comprises a name and value, as in mycookie=uniqueADDAA. Most cookies are set by the server using a short string of data that includes the web server path that is linked to the cookie, as well as the date on which the cookie expires and can be deleted by the web server:

mycookie=uniqueADDAA; expires=Thu, 01 Dec 2005 20:35:16 GMT; path=/ajaxhacks; domain=parkerriver.com

In this hack, the user also has the option to view existing cookies by clicking a button, as well as to send the existing cookie collection, including their own cookies, to a server component.

Figure 4-14 shows the web page for this application.

Figure 4-14. Fire up your own cookie

Here's what the underlying HTML looks likenothing earth shattering here. The script tags import the JavaScript that does the application's work, including initializing and using XMLHttpRequest. The HTML includes a span element for displaying a user message after the application creates a cookie:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="/books/4/254/1/html/2/js/hacks4_10.js"></script> <script type="text/javascript" src="/books/4/254/1/html/2/js/http_request.js"></script> <link rel="stylesheet" type="text/css" href="/css/hacks.css" /> <title>Cookie Factory</title> </head> <body> <h3>Bake Your Own Cookie</h3> <form action="javascript:void%200"> <p> Cookie Name: <input type="text" name= "ck_name" size="20" maxlength="20" /> </p> <p> Cookie Value: <input type="text" name= "ck_value" size="20" maxlength="20" /> </p> <p> <span ></span> </p> <p> <button type="button">Create cookie</button> </p> <p> <button type="button">View cookies</button> </p> <p> <button type="button">Send cookies</button> </p> </form> </body> </html>

When the user types a cookie name and value into the text fields and clicks the "Create cookie" button, the application generates a new cookie with a default path, domain, and expiration attribute (see the upcoming explanation). Figure 4-15 shows the browser after the user has created a new cookie.

Figure 4-15. A user-generated cookie

Figure 4-16 shows the view resulting from clicking the "View cookies" button, which shows the cookies that are accessible from responses originating from a certain domain (e.g., www.parkerriver.com). You can see that the cookie added in Figure 4-15 was identified by this cookie-reading servlet.

Figure 4-16. Reading all cookies

JavaScript

By now you are probably interested in the hacks4-10.js code, which provides the Ajax-related functionality for this application. "Use Your Own Library for XMLHttpRequest" [Hack #3] describes http_request.js, which sets up and uses XMLHttpRequest. Here's the code from hacks4-10.js:

var _host="www.parkerriver.com"; var _fpath=""; var _path="/"; //Cookie object definition function MyCookie(name,val,domain,path) { this.name=name; this.value=val; this.domain=domain; this.path=path; //The cookie lives for three days by default var dtsec=new Date( ); dtsec.setSeconds(dtsec.getSeconds( )+(60*60*24*3)); this.expires=dtsec.toGMTString( ); this.toString=function( ){ return this.name+"="+this.value+"; expires="+this.expires+ "; path="+this.path+"; domain="+this.domain; } }//End of Cookie object definition //This event handler is called when the web page //is first loaded. window.onload=function( ){ var b1 = document.getElementById("ckCreate"); var b2 = document.getElementById("ckView"); var b3 = document.getElementById("ckSend"); var _url=""; if(b1 && b2 && b3){ b1.onclick=function( ){ //The new Cookie's name/value var nm = document.getElementById("ck_nm"); var v=document.getElementById("ck_val"); try{ if(nm && nm.value && v && v.value){ var cook=new MyCookie(encodeURIComponent(nm.value), v.value,_host,_path); //Add the cookie to the current cookie collection document.cookie=cook.toString( ); //Display a user message showMsg(document.getElementById("msg"), "Cookie creation was successful."); } } catch(errv) { alert("Sorry, but we failed to create a cookie because "+ "of this error: "+errv.message); } } //Display the cookies visible from a specific host b2.onclick=function( ){ location.href="http://"+_host+_fpath+"/s/ckreader"; } //POST all available cookies to a server component b3.onclick=function( ){ _url="http://"+_host+_fpath+"/s/ckserv"; httpRequest("POST",_url,true,function( ){}, "allCookies="+encodeURIComponent(document.cookie)); } } //Create initial cookie when the application starts up _url="http://"+_host+_fpath+"/s/ckserv"; httpRequest("GET",_url,true,handleInit); } function showMsg(_id,txt){ if(_id && txt){_id.innerHTML=txt;} } //Response handler that XMLHttpRequest will use; //see Hack #3 function handleInit( ){ try{ if(request.readyState == 4){ if(request.status == 200){ var resp = request.responseXML; if(resp != null){ var outcome=resp.getElementsByTagName("outcome")[0]; var msg = document.getElementById("msg"); if(outcome != null){ if(outcome.childNodes[0].nodeValue != "success") { showMsg(msg, "Initial Cookie creation was not successful."); } } } } else { //request.status is 503 // if the application isn't available; //500 if the application has a bug alert( "A problem occurred with communicating between "+ "the XMLHttpRequest object and the server program."); } }//end outer if } catch (err) { alert("It does not appear that the server "+ "is available for this application. Please"+ " try again very soon. \\nError: "+err.message); } }

The Cookie Object

This code defines a MyCookie object, then uses that object to create the new cookie for the user. This is a small example of object-oriented JavaScript. The code declares a constructor function that sets the typical properties of a cookie:

//Cookie object definition function MyCookie(name,val,domain,path) { this.name=name; this.value=val; this.domain=domain; this.path=path; //The cookie lives for three days by default var dtsec=new Date( ); dtsec.setSeconds(dtsec.getSeconds( )+(60*60*24*3)); this.expires=dtsec.toGMTString( ); this.toString=function( ){ return this.name+"="+this.value+"; expires="+this.expires+ "; path="+this.path+"; domain="+this.domain; } }

These properties include:

  • The cookie name

  • The cookie value

  • The domain connected to the cookie, as in www.parkerriver.com

Only subsequent requests that involve the same domain will include this cookie. In other words, the browser will include a Cookie request header that includes any cookie name/value pairs associated with this domain and path.

  • The path, which further differentiates whether an HTTP request will include a particular cookie in its Cookie header

  • The expires property, a date string in Greenwich mean time (GMT) format specifying when the cookie will expire and thereafter be unavailable on this browser

Here's the code can create the cookier:

var new_cookie = new MyCookie("mycookie","myvalue","www.parkerriver.com","/ajaxhacks")

The object generates a default expiry date of three days in the future, but code can change that later. For example:

var ndate=new Date( ); //1 year from now ndate.setSeconds(ndate.getSeconds( )+(60*60*24*365)); new_cookie.expires= ndate.toGMTString( ); document.cookie=new_cookie.toString( );

The MyCookie object's toString( ) method conveniently generates a string that represents the cookie, and allows it to be set using client-side JavaScript. The previous code sample shows how this is done using the document.cookie property.

Oddly, setting document.cookie to a properly formatted cookie string has the effect of adding a new cookie to the browser's existing collection for that domain. If the code then displays the value of document.cookie, it shows not only the new cookie, but all other existing cookies as well, put together in one string.

Figure 4-17 shows an alert box displaying the value of the MyCookie object's toString( ) method.

Figure 4-17. A new cookie's string value

Another task initiated by this application is to send the values of all current cookies in a POST HTTP request. As mentioned in the earlier note, the values of all the cookies are available lumped together in a string returned by the document.cookie property. This string can easily be POSTed to an application, which can do whatever it wants with these cookie values, using the following code:

_url="http://www.parkerriver.com/s/ckserv"; httpRequest("POST",_url,true,function( ){}, "allcookies="+encodeURIComponent(document.cookie));

This call of httpRequest( ) assumes that the application does not yet have any plans for a return value; consequently, it passes an empty function literal value to the function.

Категории