Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JVM Languages

JavaScript Cookies


Dr. Dobb's Journal May 1997: JavaScript Cookies

Chuck, a software-engineering consultant, can be contacted at http://www.castle.net/~tichenor or [email protected].


Sidebar: "JavaScript Objects"

One of the most powerful features of JavaScript is not the language itself, but its interface to the browser. JavaScript has access to a variety of built-in objects and functions that allow a JavaScript program to control many aspects of the browser. One of these built-in objects is the document cookie, which lets users store persistent information in the browser's cookie file. The persistent information can be later read by other JavaScript programs. Using the JavaScript cookie, you can create web pages that can communicate with each other and have long-term memories.

In this article, I'll present a set of generic JavaScript functions that can be used to store and retrieve persistent information. These generic functions are then used to create a sample application that uses the JavaScript document cookie to communicate between two separate web pages.

The Cookie

HTTP cookies were designed to be used by server-side CGI scripts to store and retrieve persistent information on web clients. With the advent of JavaScript and the document cookie, you can run scripts on the browser to manipulate HTTP cookies. A cookie is a named string that can optionally contain location, expiration, and security attributes. The JavaScript document.cookie property provides a window into the browser cookie file. When this property is read, it returns a semicolon-delimited list of "name=value" pairs.

For security, only pairs that pertain to the particular domain and path of the current URL are returned. This prevents unscrupulous JavaScripters from gaining access to private cookies (refer to the ReadCookie method in COOKLIB.JS, available electronically; see "Availability," page 3). To store a new cookie, write a "name=value" string to the document.cookie property; for example, document.cookie='FredsWife=Wilma' will store a cookie named "FredsWife" with the value "Wilma". You can use the same method to update a previously stored cookie to a new value. For example, document.cookie='FredsWife=Betty' will update the cookie named "FredsWife" to the value "Betty".

To assure long-term persistence of your cookie data, you must append an expiration date, using the format expires=GMTExpirationDate to your cookie. You can create GMT date strings using the Date.toGMTString() method. Again for security, you can specify the domain, path, and secure attribute values for the cookie; see the WriteCookie method of COOKLIB.JS. The expiration date attribute of the cookie is needed to delete it. You delete a cookie by storing it with an expiration date that was in the past. Immediate cookie deletion is not guaranteed. The cookie value may persist until the end of the current browser session; see the DeleteCookie method in COOKLIB.JS.

Persistent Objects

The approach I've just described works fine for storing individual pieces of data, but is insufficient for storing an entire object. Fortunately, JavaScript objects are more similar to arrays than to actual C++ or Java objects (see the text box "JavaScript Objects" for details). Their similarity to arrays makes them easier to store generically. The methods (which will be described shortly) must be attached to objects using the "Object.Method=FunctionName" syntax.

The StorePersistently object methods in OCOOKLIB.JS (available electronically) show how to store an object with a given name in the cookie. They create a composite string of delimited "property name =property value" pairs that is then stored as a single cookie. The choice of '|' as a delimiter is arbitrary and may be changed to suit your application. There are two versions of the StorePersistently method -- one that works under Netscape 3.0, and another that works under Netscape 2.0 and 3.0. If you use the 2.0 version, you must ensure that all object properties that contain data values precede all object properties that contain function values. You must also ensure that the last data property is named endDataMembers. Adhering to this convention will guarantee that only the data properties of your objects are stored in the cookie. This saves space, because when you store a function in the cookie, the entire text of the function is stored. Version 3.0 of the StorePersistently method lets you create free-form objects. It uses the typeof operator to make sure that no object properties of type "function" are stored in the cookie.

The RetrievePersistently object method (OCOOKLIB.JS) shows how to retrieve an object from the cookie. This method is called from an existing object. The method parses the composite string, which was retrieved from the cookie using the given object name. Each parsed property name=property value string is used to update or create the associated property in the object using the Object[PropertyName]=PropertyValue associative array style syntax.

You might be thinking that it would be easier to create a single cookie for each property, instead of creating a single delimited composite that holds all the properties. I store the object in a single cookie instead of multiple cookies because Netscape has placed a 20-cookie limit on each domain. You don't want to use up all your cookies on a single object. Netscape has also limited cookie size to 4K and the total number of cookies to 300. Web clients, including Netscape, will likely lift these arbitrary limitations if use of client-side persistence becomes more prevalent.

Putting it all Together

Using the generalized JavaScript libraries discussed here, I created a custom catalog application for the fictitious "Bolts 'R' Us" company. This application is comprised of two HTML pages. The first (NANDB.HTM, available electronically) displays a view of all available bolts, and the second (FULLVIEW.HTM) displays the details of the individual bolts and lets users browse. The first page writes information to the cookie, and the second page reads the information to determine what to display. Using JavaScript and the cookie, two pages can be used to display information that would require nine static HTML pages. VIEWINFO.JS (available electronically) is the JavaScript code that glues the two pages together. This code contains the object-constructor methods that are used to create the objects that are stored into and retrieved from the cookie. The ViewInfo object is used to describe all the characteristics of an individual bolt. ViewPageInfo is a composite object containing an array of ViewInfo objects (one per bolt), navigational properties, and general appearance properties.

When the first page loads, the page header stores the properties for the body background image and text color in the cookie using the SetBack method from VIEWINFO.JS. It then creates a bolts-description array, which it stores in the cookie. The bolt-description array consists of ViewInfo structures that each contain information for a single bolt: its price and details of its image file (filename, thumbnail dimensions, full-view dimensions, title, and description). One cookie is used for each bolt.

The body of the page contains another script that iterates through the bolt ViewInfo array in order to create a table that has one bolt thumbnail per table cell. The ViewInfo object method ViewInfo_WriteDoc (VIEWINFO.JS) creates the actual HTML code that is written to the document in order to create the thumbnail cells. Figure 1 shows how the first page looks when loaded. ViewInfo_WriteDoc creates a table cell that contains an anchor tag that links to the second page. The tag is defined so that the JavaScript DoClickPic method is called for the onclick event, and the DoMsg method is called for the onMouseOver event. The DoClickPic method stores the index parameter in the cookie. This parameter is the index of the ViewInfo array element that describes the bolt that was clicked by the user. The second page is then loaded per the anchor tag HREF attribute. When it loads, it reads the view information from the cookie and displays the view for the bolt with the index that was just stored by the DoClickPic method.

The entire body of the second page is created dynamically using JavaScript. A ViewPageInfo object is created and its associated WriteDoc method is invoked to generate the HTML that comprises the document body. The ViewPageInfo object constructor reads all the properties that were stored in the cookie by the first page. The ViewPageInfo_WriteDoc method creates an HTML document that displays the large bolt image together with a title, description, price, and navigational buttons. Figure 2 shows the second page.

The bolt-image information is read from the current ViewInfo array element by indexing the ViewPageInfo.view array property with the ViewPageInfo.curIndex property. Anchor tags bracketing the navigation buttons are used to invoke the JavaScript methods DoPrev, DoNext, and DoBack.

DoPrev causes the index of the previous ViewInfo element to be stored in the cookie before it reloads the current page; DoNext causes the same to happen for the next ViewInfo element. Storing a new index before reloading the page causes the page to display a different bolt. If the DoBack method is invoked, the first page is loaded (the page specified in the ViewPageInfo.backLink property). The same thing happens if either the DoPrev or DoNext methods cause the current index to go out of range. The ViewPageInfo _WriteDoc method has a sanity check that prevents a page from being loaded when there are no cookie parameters stored. If the ViewInfoMaxIndex cookie cannot be found, a static error message is displayed instead of those nasty JavaScript pop-up error boxes.

Other Applications

Another important application of JavaScript cookies is persistent storage of user preferences. For example, when a user visits your site, you might want to store their favorite background color, name, display preferences, and so on. This information can be encapsulated in a single preferences object that can be stored and retrieved using the JavaScript methods just described. Remember to supply an expiration date when storing cookies for the long term. If you do not provide an expiration date, the stored-cookie information will be discarded when the browser exits...at least, that's how it's supposed to work.

Conclusion

The JavaScript document cookie puts browser-side persistence within the reach of web developers everywhere. The JavaScript methods described here make object persistence even easier. With these tools, you can create web pages with long-term memory, web pages that replace CGI scripts, or web pages that communicate with each other. These features will allow you to create sites that are more user friendly and less burdensome to HTTP servers.

DDJ


Copyright © 1997, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.