ScriptHead: JavaScript SmartForms By Rick Scott, December 31, 1998 Welcome, JavaScripters of all browsular persuasions, to Millennium Eve ... Hope you had a pleasant and restful holiday full of good cheer and solid family values and all that? ;-) Well the time has come to recover some of your eggnog-diluted ambition and dive into some good hard honest JS scripting. So sit back, degauss your monitors, flex your carpi ulnaris, and prepare to be SmartFormed! Cookies, cookies, cookies . . . You've read about them, experienced them first hand (whether you know it or not), and perhaps even coveted them (or at least the ability to create/manipulate them). In this month's column, we'll create a set of JavaScript SmartForms, a trio of HTML forms that derive a good chunk of their vital data from a user profile. And where is this user profile stored? You guessed it: In a cookie. Compatibility-wise, the JS SmartForms should work just fine in Netscape 3.x (and higher) and Internet Explorer 3.x (and higher) browsers. With one important exception: If you are running IE 3.x and you open a SmartForm that is stored on a local hard drive, it will not work. How come? Because IE 3.x only processes cookies for HTML documents that are retrieved with the HTTP protocol; i.e., documents that you open from remote servers. (Documents that you open from your local drive are retrieved with the FILE protocol.) The moral is: If you are using IE 3.x to test your SmartForm scripts, you will have to upload your documents to a remote server to get the cookies to work. [Suggestion: Upgrade to IE 4.x already! You'll (probably) love it.] SmartForms Guided Tour Follow these directions to put the JS SmartForms through their full JavaScript paces: 1.First of all, make sure that your browser is set to accept cookies. In Netscape, choose Edit, Preferences, Advanced, and select Accept All Cookies. If you want to watch the cookie-creation process in action, check Warn Me Before Accepting A Cookie; this causes Netscape to inform you whenever it's about to create/modify a cookie. In Internet Explorer, choose View, Internet Options, Advanced, and select Always Accept Cookies. Or, if you want to watch the cookie-creation process, select Prompt Before Accepting Cookies. 2.Optional: Download the JavaScript SmartForms files and unzip/install them on your own computer. That way, you can view the SmartForms source code while you're reading the upcoming analysis. 3.If you installed SmartForms on your computer, open the index.htm file in your browser. If not, click here to open index.htm from the DevHead server. If this is the first time you've accessed index.htm, the User Profile form will appear with the cursor pulsing cheerily in the Name field, urging you to enter your user-profile information. If not, the SmartForms HomePage will appear, in which case you should skip directly to Step 5 of this procedure. Enter your name, then click on Accept Profile. An alert box appears prompting you to enter your age (the next field in the User Profile form). Click on OK to close the alert box, select your age from the Age list box, then click on Accept Profile again. An alert box prompts you to enter your sex (the next field in the form). And so on. Clicking on the Accept Profile button causes JS to validate the User Profile form; i.e., to ensure that appropriate user-entered data appears in each form field. Complete your user profile. Feel free to enter utterly erroneous and/or misleading information! Be sure to enter a fake VISA number (1234-1234-1234-1234 will do), so that no one can wander over to your monitor and "borrow" your credit-card number while you're preparing an innocent pot of Darjeeling tea . . . 4.Click on Accept Profile to save your user-profile data to a cookie. (A prompt will appear to this effect, if you selected the appropriate option in Netscape or Internet Explorer, as explained in Step 1.) The SmartForms HomePage appears. Note that the name you entered in your user profile has been appended to the "Greetings, . . . !" line. 5.Click on the Feedback SmartForm link to open the Feedback SmartForm. Note that your name and email address -- as entered in your user profile -- are correctly specified. Normally, you'd have to fill these fields in manually, but the SmartForm is "smart" enough to fill them in for you automatically! 6.Click on the SmartForms Home link to return to the SmartForms HomePage. Now click on the Order SmartForm link to open the Order SmartForm. Note that your name, city, state, zip code, VISA number and expiration date are all correctly specified. Again, in a non-SmartForm form, you'd have to fill all these fields in manually. Observe the order information. The values of the first two lines, Order and Price, are fixed (for this sample order form). But the values of the remaining lines depend on the state you selected in your user profile. If you selected NY, a line specifying the NY tax will appear; if you selected any other state, no tax line will appear. If you selected AK (Alaska) or HI (Hawaii), the shipping/handling fee is set to $10.00; if you selected any other state, shipping/handling is set to $5.00. In addition, when you click on Submit, a refuse-to-sell message will appear if you set the Age field in your user profile to less than 50. To try out all these user-profile-dependent actions, click on the User Profile button to open the User Profile page, modify the State and/or Age fields of your profile, click on Accept Profile to open the SmartForms Home, then click on the Order SmartForm link and observe the results. 7.Return to the SmartForms HomePage. Click on the Survey SmartForm link to open the Survey SmartForm. As indicated at the top of the page, the SmartForm engine customized this survey to your specific user profile. There are three different surveys that this sample Survey SmartForm generates: One for boys under 13, one for women over 69, and one for everyone else (men and women 13-69). Each survey displays the same six interests in the left column and six different (customized) interests in the right column. Note that this is a mere taste of the possibilities inherent in such a technique: If you were so inclined, you could create not three but 300 different user-profile-dependent surveys! To see each of the three surveys, click on User Profile, set the Age and Sex fields of your profile as described above, click on Accept Profile, then click on the Survey SmartForm link. The Big Picture Here's what happens at the macro level -- as opposed to the micro level, which we'll examine in The Little Picture section of this column -- when you open the SmartForms index.htm file: The user-profile cookie is retrieved; i.e., the cookie file is read. If the user-profile cookie does not exist or is empty, the User Profile form (profile.htm) appears with blank data fields, "forcing" the user to create a user profile. Clicking on the Accept Profile button validates the profile data fields. If all fields are valid, it saves the data to a user-profile cookie, then opens the SmartForms HomePage (homepage.htm). Clicking on the Clear Profile button blanks out all form fields in preparation for a new user profile. If the user-profile cookie exists and contains a user profile, the SmartForms HomePage is displayed (without any intervening User Profile form). Clicking on a SmartForm link (Feedback, Order, or Survey) opens that page. Each SmartForm page begins by retrieving the user-profile cookie and parsing its data into separate chunks (name, age, sex, city, etc.). The document.write() method is then used to dynamically write the desired data chunk into the appropriate place in the SmartForm. For example, in the Feedback SmartForm, the user's name and email address are grabbed from the user-profile cookie and written dynamically to the page. In the Order SmartForm, the user's name, city, state, zip code, VISA number and expiration date are all grabbed and written. In addition, the user's state and age figure into the page workings (as described in Step 3 of the SmartForms Guided Tour). In the Survey SmartForm, no user data is written directly to the page. However, the user's age and sex determine the composition of the survey (as described in Step 3 of the Guided Tour). Clicking on a (Create/Modify) User Profile button brings one back to the User Profile page. If the user-profile cookie does not exist or is empty, the User Profile form comes up blank, just begging to be filled in. If the cookie exists and contains a user profile, the User Profile form comes up with all its data fields populated, ready to be modified. Cookies "Cookies cookies everywhere, but not a crumb to eat . . ." Whence the tantalizing term cookie? Well, the original term, magic cookie, was coined long long ago by batch-processing UNIX codeheads to denote a small chunk of secret, password-like data that permitted access to privileged computer information. As mysterious as (magic) cookies may sound, they're really rather mundane. In a nutshell: A cookie is a relatively small amount of data (<= 4K) that is stored in a file on a user's local hard disk (e.g., their C drive). This data is read by a browser and used to achieve some degree of "long-term memory" over different browser pages and sessions. All of a page's variable values (the contents and settings of its text boxes, list boxes, checkboxes, radio buttons, JS variables, etc.) become unavailable the moment the page is closed, another page is opened, or the browser itself is closed. Cookies provide a way out by enabling these values to persist by being stored on a hard disk. To take a concrete example, recall the SmartForms User Profile Name field in which you entered your name. Normally your name entry would become unavailable as soon as you opened another page (as just explained). Yet you opened several other pages in your guided tour -- the SmartForms HomePage, the Feedback SmartForm, and the Order SmartForm -- on which your name entry appeared plain as day. All thanks to cookies. So how do cookies work in JavaScript? In theory it's simple: Every HTML document possesses a document.cookie property. To retrieve the data that a cookie contains, you read its document.cookie property. This property, which is a single string, specifies a name and its associated value: A name/value pair. To store data in a cookie, you write a properly formatted name/value string to document.cookie. To delete a cookie, you write a properly formatted expire string to document.cookie that causes the cookie to expire immediately. And that's about all there is to it! So why are cookies considered such an advanced JS topic? Because, in practice, the code that is needed to read and write the document.cookie property is complex and a bit . . . counterintuitive. But, take heart: Help is at hand! The SDFD Cookies Library Every self-respecting JavaScript programmer eventually settles on a favorite cookie library: A set of functions that enables one to retrieve, store, and delete cookies. In the beginning (i.e., two-three years ago), you had pretty much one choice: Bill Dortch's famed cookie functions. Several Dortch-based cookies libraries followed: Most notably Nick Heinle's. Then David Flanagan exploded onto the cookies scene with his excellent object-oriented approach to cookie management. At least one distinguished Flanagan variant ensued: Chris Doemel's. The cookies library I use for the JS SmartForms is a hybrid of the Dortch and Flanagan libraries (with a dollop of Doemel thrown in for good measure): The Scott/Doemel/Flanagan/Dortch (aka the SDFD) Cookies Library! ;-) It's a best-of-both-worlds library, combining the thoroughness of Dortch's cookie functions with the object-oriented design of Flanagan's cookies code. Space does not permit me to perform a detailed analysis of the SDFD Library. (Wipe that grin off your face . . .) So you'll have to content yourselves with the following thumbnail sketch: The Cookie() constructor function enables JS scripters to create Cookie objects. The Cookie_get(), Cookie_store, and Cookie_del() functions enable scripters to retrieve, store, and delete Cookie objects. The prototype property is used to make all these functions into methods of a Cookie object, which are called as follows: Cookie.get(),Cookie.store(), and Cookie.del(). Feel free to use the SDFD Library for your own cookie-powered pages. Once you get the hang of it, it's really quite easy to use. Here's a quick-reference guide to SDFD usage: To create a Cookie object: cookieObj = new Cookie(name [, expires] [, domain] [, path] [, isSecure]); name, which is the only required Cookie() argument, specifies the name of the name/value string (as discussed on the previous page) that is stored in the cookie. For a description of the other arguments, refer to cookies.js. To retrieve data from a cookie: myCookie = new Cookie("cookieName"); cookieData = myCookie.get(); The above code will retrieve the data from an existing cookie whose name (of its name/value string) is "cookieName." To store data in a cookie: myCookie = new Cookie("cookieName", new Date(1999,11,1)); myData = "Hi there!"; myCookie.store(myData); The above code will store the specified myData data in a cookie whose name (of its name/value string) is "cookieName." If a cookie with this name already exists, its data will be overwritten with the new myData data. Unless you want the cookie to expire as soon as the user finishes their current browser session, you should specify an expires argument, such as the one above -- new Date(1999,11,1) -- which causes the cookie to expire on December 1st, 1999. To delete a cookie: myCookie = new Cookie("cookieName"); myCookie.del(); The above code will delete an existing cookie whose name (of its name/value string) is "cookieName." The Little Picture Here, as promised, is a sketch of how things work at the SmartForms micro level: index.htm The JS Cookie Library (cookies.js) is loaded: The user-profile cookie is retrieved. If it exists and contains a profile, the SmartForms HomePage is opened. If not, the Profile Form page is opened: var upCookie = new Cookie("upData"); if (upCookie.get() != "") top.location.href = "homepage.htm" else top.location.href = "profile.htm" profile.htm The JS Cookie Library and the User-Profile Validation Library are loaded: A user-profile cookie object is created and the cookie is retrieved (in the init() function, which is called at page load). If the cookie exists and contains a profile, the profile data is parsed into chunks and stored in upDataArray[], then these chunks are used to fill in all the User Profile fields. If the cookie doesn't exist or is empty, the User Profile fields are left blank and the cursor is placed in the Name field: var upCookie = new Cookie("upData", new Date(1999, 11, 1)); . . .
. . . function init() { var form = document.profileFrm; var upCookieData = upCookie.get(); if (upCookieData != "") { var upDataArray = upCookieData.split("|"); form.nameTxt.value = upDataArray[0]; form.ageSel.options[upDataArray[1]].selected = true; . . . form.expmonthSel.options[upDataArray[9]].selected = true; form.expyearSel.options[upDataArray[10]].selected = true; } else { form.nameTxt.focus(); } } The saveProfile() function, which is called once the User Profile form data has successfully validated, concatenates all of the user-profile data into a long string (upData), then stores this string in the user-profile cookie (upCookie). The act of storing the string overwrites the previous contents of the cookie: function saveProfile(form) { var upData = form.nameTxt.value + "|"; upData += form.ageSel.selectedIndex + "|"; upData += form.sexSel.selectedIndex + "|"; . . . upData += form.expmonthSel.selectedIndex + "|"; upData += form.expyearSel.selectedIndex; upCookie.store(upData); } feedback.htm The JS Cookie Library is loaded: The user-profile cookie is retrieved. If it exists and contains a profile, the profile data is parsed into chunks and stored in upDataArray[]: var upCookie = new Cookie("upData"); var upCookieData = upCookie.get(); if (upCookieData != "") var upDataArray = upCookieData.split("|"); These chunks are used in conjunction with document.write() to dynamically fill in the Name and EMail data fields that are displayed in the form: Name:order.htm, survey.htm The JS code in these two files is very similar to that in feedback.htm. I'll let you figure out its inner workings on your own! Conclusion Dat's All Folks! Well, for once I'm (almost) speechless . . . Cookies'll do it to you every time! ;-) To deploy a SmartForm or two on your own pages, download/unzip/install the constituent files and customize them to meet your needs. If you come up with something you're particularly proud of, send DevHead your URL so we can admire your handiwork. Happy JavaScripting! Rick Scott