DAY 14

Working with Documents and User Interface Functions


CONTENTS


A key goal of VBScript is to enable you to make your documents come alive. With VBScript, your documents are no longer just another pretty document for the user to stare at. Instead, your document becomes an interactive application. It responds to the user's requests, obtains information from the user, and carries out processing at his request. By now you know a lot of what it takes to make a document come alive. You've seen how to put together a script that interacts with component objects on the Web page. Examples of integrating intrinsic controls, ActiveX objects, and Java applets have appeared on previous days, along with techniques for wrapping code around them to let your scripts interact with them. But you haven't yet seen all the details of how to make the page itself be responsive above and beyond the components placed on it.

The details of scripting responsive, interactive Web pages is the topic today. Some specific techniques allow you to interact with the user right from your code, without going through an integrated component. You have already seen a simple form of one of these inherent capabilities, the message box function MsgBox. Now you will learn how to use MsgBox to its fullest and see a similar function supported by Internet Explorer that you can make use of, called Alert. Also presented in detail is the InputBox function, which offers even more interaction possibilities than the message box. Finally, the document object that represents the page itself is addressed. You can control generation of that document page through code as well as through the standard HTML statements behind it.

The most exciting aspect of these capabilities is that they allow you to perform advanced interaction with the user. If you come from other graphical programming environments, you may have felt constrained by VBScript so far. If you're used to writing programs that display an additional form or window for each piece of user interaction, the one-page model central to VBScript has probably left you wondering "How do I easily give my user dynamic feedback, prompt him for the next piece of information, or generate a different form based on changing conditions?" The user interface approaches addressed here give you much of the answer. Today's lesson highlights how to implement interaction without going through integrated components. Even if you know about the message box and input box from Visual Basic or another background, don't bypass this chapter entirely. The fundamental functions are introduced first, but a detailed look at the document.write method and dynamically generating HTML follows. This culminates in an example at the end of the lesson that shows how message box capabilities and document.write can be combined to provide a user-customizable page at load time. Then the remaining pieces of the picture are wrapped up on Day 18, "Advanced User Interface and Browser Object Techniques," as the tradeoffs of user interaction across single or multiple pages are discussed.

Giving the User the Message Through Message Boxes

Sometimes, particularly in a programming language, simple is beautiful. An easy-to-use programming function or element is less likely to cause you bugs, which saves you time, effort, and the pain of banging your head on the monitor in frustration. Simple means good, clear, maintainable code. The message box function is just that-good and simple!

You have seen examples of the message box in earlier chapters. For example, you can insert a statement in your code that displays a small window with the message Break time! with just 20 characters of typing:

MsgBox "Break time!"

When this code statement is carried out, a window containing this message pops up in the middle of the screen. Not only does the user see this message in a nice little window, but that window even comes with a handy acknowledgment button. The window hangs around until the user clicks on the button to make it go away.

VBScript offers another way to send a message to your user: You can use the Alert function. This function was first used in the JavaScript language. It actually isn't a part of the VBScript language, but is a function supported by the Internet Explorer host environment. Because you have access to host objects from VBScript (covered in more detail on Day 18), you can use Alert. Like MsgBox, Alert displays the text in a message window and provides a button that must be selected to acknowledge the message. The windows generated by Alert and MsgBox are shown in Figure 14.1.

Figure 14.1 : The Alert and MsgBox message windows.

One obvious difference between these two functions is shown in Figure 14.1. Alert places a title at the top of the window that says Microsoft Internet Explorer and uses the ! icon; MsgBox provides the default title Visual Basic and does not show an icon.

Line Separation

The MsgBox function allows extensive customization of the information it presents. The first parameter to this function, as you have seen, provides the message that is displayed to the user. If you want this message to be provided as more than one line when the message is presented, you simply separate each desired line with the carriage return line feed constant vbCrLf which you must define. For example, the following sample displays "Line1", "Line2", and "Line3", each on a separate line within the message box:

Dim vbCrLf : vbCrLf = Chr(13) & Chr(10)
MsgBox "Line1" & vbCrLf & "Line2" & vbCrLf & "Line3"

In addition to using vbCrLf to force a line separation, you could also use just Chr(13) or Chr(13) & Chr(10). These are all different ways of telling VBScript to separate a line. VBScript knows to separate a line if it sees a carriage return character or a line feed character, represented by these constants and ASCII character codes. These invisible characters don't show up on the screen, but they do convey formatting information.

You may be wondering why you have so many choices about how to request a line separation. It used to be that for a particular operating system you had to supply exactly the right characters from a language to control line separation. For example, you had to use the command Chr(13) on some systems, and Chr(13) & Chr(10) on other types of systems. VBScript is smart enough to relieve you of this burden. If it gets any of these characters, it knows you want to separate a line. It won't be picky.

Note
Alert offers capabilities similar to MsgBox in the line separation area. The rest of this section focuses specifically on the MsgBox function, since it is used for a wider variety of situations than Alert.

Buttons and Titles

Figure 14.1 shows a plain-looking message box that provides a minimum amount of interaction. First, let's consider the issue of interaction. The user could choose to click on OK, or he could choose to click on OK. There are no other choices! The purpose of forcing the user to select OK is to ensure that he has read the message presented. The OK button, in this case, is simply an acknowledgment button.

There are ways to use MsgBox to get much more information from the user than simply an acknowledgment. The second parameter of the function is used to specify message box attributes. One attribute that can be specified is the type of button choices that the message box can provide to the user. Consequently, this affects the type of return code information that is provided back to your code.

Several types of button choice attributes may be designated. Each attribute can be specified by a specific integer number. To make working with these attributes easier and make code that uses them more maintainable, a file is provided on the CD-ROM to define them. The file is constant.txt in the shared\tools directory. The needed declaration lines can be copied and pasted to your own script. The constant names, values, and purposes are summarized in Table 14.1. Normally if you use the supplied constant definitions you will refer to these attributes by constant name only, and will not have to use the value.

Table 14.1. VBScript button constants.
Constant NameValue Purpose
vbOK
0
Show only OK button
vbOkCancel
1
Show OK and Cancel buttons
vbAbortRetryIgnore
2
Show Abort, Retry, and Ignore buttons
vbYesNoCancel
3
Show Yes, No, and Cancel buttons
vbYesNo
4
Show Yes and No buttons
vbRetryCancel
5
Show Retry and Cancel buttons

The message box shown in Figure 14.1 has the OK button. This button is provided by default if you do not supply a second parameter to designate the button attribute. A message that presents just an OK button is typically used to present information to the user and have him acknowledge that the information has been read.

You can use button attribute constants to request different combinations of buttons as well. All the available combinations are documented in Table 14.1. Most of these combinations give the user the opportunity to provide more feedback to the script than just a simple acknowledgment. The vbYesNoCancel constant, for example, provides three choices for the user. The script can then interpret which button the user selected and perform further processing based on that response.

The approach to interpreting the user's response from a script is considered next. But first, consider the cosmetic aspects of the message box. An example of a vbYesNoCancel message box appears in Figure 14.2.

Figure 14.2 : A message box with Yes, No, and Cancel buttons.

The line of code that produced this message box is

rc = MsgBox( "rc = MsgBox ""Text"", vbYesNoCancel + vbExclamation, _
      ""Title"" ", vbYesNoCancel + vbExclamation, "vbYesNoCancel")

Note
When you want a quote to be displayed within a string, use two consecutive quotes. Only one will appear in your string, and the string will not be terminated by the occurrence of the double quotes. This is the technique used in the code example, which prints out a message box that has quotes as part of the message string. Because a double quote (represented by two double quotes) needs to be printed at the end of the main string (closed by a double quote), you see three double quotes at the end.

The preceding is a complicated-looking line of code at first glance, but that is largely because the message that is provided in the first parameter contains sample syntax for a message box. For the sake of clarity, assume you wanted to use the same type of message box to display the question Do you use VBScript?. The call to generate that question with Yes, No, and Cancel buttons would be

rc = MsgBox( "Do you use VBScript?", vbYesNoCancel + vbExclamation, "My Title")

Consider this call a piece at a time. First of all, rc is the variable that is used here to receive the return code from the function call. This variable will be filled with a number that indicates the user's button choice. Then consider the three parameters to the MsgBox function. The first parameter is simply the message or question that you want to display. Turn your attention next to the third parameter (an easier one!). That parameter indicates the title that is displayed on the caption area of the message box. If no third parameter is supplied, Visual Basic will show up as the default title.

Finally, consider the second parameter. The values you supply here are codes that determine the attributes of the message box. Table 14.1 lists the attribute constant values you can use for certain combinations of buttons. The intrinsic constant vbYesNoCancel is used in the preceding sample to cause the Yes, No, and Cancel buttons to appear. When buttons are requested, the message box automatically takes care of generating them and returning a predefined number for that specific button through the function's return code. So the vbYesNoCancel constant in the second parameter causes generation of a window with three specific buttons, and each button will cause a specific documented number to be generated when it is clicked.

But that's not the whole story of the second parameter. The second parameter has two pieces joined by a plus sign. The button indicator code is on the left side. What's that on the right side? It's a value that indicates the icon to display with the message box. These values are represented by VBScript user-defined constant declarations in shared\tools\constant.txt on the CD-ROM. Just like the button value, they can be one of the entries in Table 14.2.

Table 14.2. VBScript message box icon values.
Constant Name
Value
Purpose
vbCritical
16
Show an X, used for a critical error
vbQuestion
32
Show a question mark, used for a question
vbExclamation
48
Show an exclamation point, used for a warning
vbInformation
64
Show an I, used for an informational message

The attribute parameter can be used to convey two pieces of information to the message box function. This simply requires adding the button attribute and icon attribute value together. For example, the vbOKCancel value is 1 and the vbCritical icon value is 16. Normally you would request this combination of attributes with a statement like this:

MsgBox "Testing", vbOKCancel + vbCritical, "My Title"

But you could achieve the same result with this statement:

MsgBox "Testing", 17, "My Title"

The first approach is recommended because it makes for more readable, more maintainable code. But both work just the same. Even the combined number uniquely identifies both attributes because command button values are 5 and less, and icon values are 16 and higher. All you really have to know to use these effectively, however, is that you can combine both values into this one parameter.

Look again at Figure 14.2 to see an example of the exclamation point icon. This was produced, along with the Yes, No, and Cancel buttons, by this line of code:

rc = MsgBox( "rc = MsgBox ""Text"", vbYesNoCancel + vbExclamation, ""Title""", _
      vbYesNoCancel + vbExclamation, "vbYesNoCancel")

Figure 14.3 shows an example of the information icon on a message box.

Figure 14.3 : A message box with the information icon.

This message box has only the OK button. It was generated by the following statement:

rc = MsgBox( "rc = MsgBox ""Text"", vbOKOnly + vbInformation, _
     ""Title"" ",vbOKonly + vbInformation, "vbOKOnly")

The value of the vbOKOnly constant is 0. Therefore, this code would work exactly the same if the following statement were used:

rc = MsgBox( "rc = MsgBox ""Text"", vbInformation, ""Title"" ", vbInformation, _
    "vbOKOnly")

Figure 14.4 shows a message box that uses the question mark icon, along with Yes and No buttons. That message box was generated by the following statement:

Figure 14.4 : A message box with a question mark icon and Yes and No buttons.

rc = MsgBox( "rc = MsgBox ""Text"", vbYesNo + vbQuestion, ""Title"" ", _
      vbYesNo + vbQuestion, "vbYesNo")

Figure 14.5 rounds out the list of icon types. This figure shows an example of the critical error icon, combined with the OK and Cancel buttons. It was produced by this line of code:

Figure 14.5 : A message box with a critical error icon and OK and Cancel buttons.

rc = MsgBox( "rc = MsgBox ""Text"", vbOKCancel + vbCritical, ""Title"" ", _
     vbOKCancel + vbCritical, "vbOKCancel")

The choice of which icon to use in which situation should be based on the criteria that the icon names imply. Informational feedback that is not an error condition should use the information icon. If you are asking the user a direct question, use a question mark icon. Less severe errors are typically presented with the exclamation point icon. Very severe errors that can bring a script to a halt or invalidate results would warrant the use of the critical error icon.

Each of the code statements in the icon type illustrates the use of a variable to capture the MsgBox return code. When this function is used, it sends a return value back to the statement it was called from. This return code can be assigned to a variable of any name, although the convention of rc for return code is often used. The return code will indicate which button the user selected. This value will be one of the ones shown in Table 14.3.

Table 14.3. VBScript button response values.
Constant Name
Value
Purpose
vbOK
1
Returned by MsgBox if OK is selected
vbCancel
2
Returned by MsgBox if Cancel is selected
vbAbort
3
Returned by MsgBox if Abort is selected
vbRetry
4
Returned by MsgBox if Retry is selected
vbIgnore
5
Returned by MsgBox if Ignore is selected
vbYes
6
Returned by MsgBox if Yes is selected
vbNo
7
Returned by MsgBox if No is selected

If you have used programs in a Windows environment, you probably know one very important aspect of the message box window: It is modal. This means that when a message box is presented to the user, he must respond to it before he can interact further with that Web page. This is great news from a script programming standpoint. When a script puts up a message box, you know that by the time the next code statement is carried out, the user will have already provided a response to that message. This gives you a high degree of control over the interaction. You know the user has to respond when you offer a message, and you know that in the statement after the message you have a record of the user's response.

Your script can take further action based on the return code. An example of code that evaluates the return code from MsgBox is shown in Listing 14.1. This code makes use of the global constant declarations in the file shared/tools/constant.txt on the CD-ROM.


Listing 14.1. Evaluating the return code from MsgBox.
Sub cmdYesNoCan_OnClick
    dim strFeedback ' Feedback string
    dim rc ' return code from message box call
    rc = MsgBox( "rc = MsgBox ""Text"", vbYesNoCancel + vbExclamation, _
       ""Title""", _
         vbYesNoCancel + vbExclamation, "vbYesNoCancel")

    strFeedback = "Response was " & rc & "." & vbCrLf
    if rc = vbYes then
         strFeedback = strFeedback & _
         "This is equal to vbYes and indicates Yes was clicked."
    elseif rc = vbNo then
         strFeedback = strFeedback & _
         "This is equal to vbNo and indicates No was clicked."
    elseif rc = vbCancel then
         strFeedback = strFeedback & _
         "This is equal to vbCancel, indicates Cancel clicked."
    else
         strFeedback = strFeedback & _
        "This is not equal to any expected constant."
    end if

    msgbox strFeedback, vbOKOnly, "vbYesNoCancel Return Code"
end sub

The message box is generated by the third line of this code. Since the vbYesNoCancel attribute value is specified, the message box will have only three buttons-the Yes button, the No button, and the Cancel button. Therefore, these are the only possible buttons the user can interact with. As a result, the only possible values that can result from this call to the MsgBox function are vbYes, vbNo, and vbCancel. The code in the last half of the listing compares the return code to each of these possible values to build the final result string.

The message box provides yet another interaction choice to the user. You can specify a help file name and help file context in a fourth and fifth parameter to the function. The help file indicates a file with help information that corresponds to the message. The help file context identifies a specific topic within that help file to be displayed. If help file information is provided, a help button will also appear on the message box. Display of the help file will only occur if the user clicks on the help button or selects the f1 key. Help information is typically used to provide more details on an error message for the user.

Now you have been exposed to all the parameters of the message box. The only parameter that must be specified is the message parameter. The rest are optional. They are summarized here for your reference:

ResultVariable = MsgBox(prompt_string, optional_button_and_icon_values,
optional_title, optional_helpfile, optional_context)

Why might you want to get a user response through a message box? Perhaps your script detects invalid input and needs to know whether the user wants to respecify it or ignore it. Or maybe you need to ask a series of yes-and-no questions to determine how to carry out a calculation for a user. Or, if a calculation ends up taking many loops, you might want to present the user with a choice to continue or cancel the operation. In situations like these, feedback from the user can be crucial to the operation of your script. If you had to get this feedback by interacting with form controls every time, your pages would look intimidating to the user. They might contain prompt fields that are rarely used, and the user's interaction task would be much more complex. Instead of a window popping up before the user's eyes in the middle of the screen, the user would have to locate the equivalent field. For all these reasons, message boxes can play a very important role in your script user interface design.

Note
This discussion focuses on using MsgBox as a function. MsgBox can also be used as a subroutine call. The difference in that case is that a subroutine call does not return a value. Simply call it as a statement rather than treating it as a function and capturing its value in a return code if you don't care about the return code. Here's an example:
MsgBox "rc = MsgBox ""Text"", vbOKCancel + vbCritical,_
     ""Title""",vbOKCancel + vbCritical, "vbOKCancel"
This statement will not provide a value back. InputBox, which is considered next, can also be called as a function or a call. The function-based approach is considered here. It is the more common and powerful approach because you can take action base on the return codes.

Input Boxes

Message boxes can greatly extend the power of your scripts. You can provide feedback to the user without having to run it through the Web page. You can get responses from the user that the script can act on, all in a separate window that the user must interact with before proceeding. The message box model works great for collecting responses unless you want more feedback than simply yes, no, cancel, abort, retry, or ignore. But in the case of certain data on a form, you might need more information from the user before submitting the data. The information you need might be additional string information such as alternative supplier information. Ideally, you want to collect this information in a supplemental window to your page for the same reasons that message boxes are handy. If you had to provide additional input fields for just a few special cases, your page could be quite messy. It might be hard to highlight the appropriate fields for the user, and it would be difficult to ensure that all the information has been provided as you proceed through a sequence of steps. Fortunately, the message box has a close cousin that can come to the rescue in cases like this. The input box function InputBox provides a separate modal window much like the message box. It can present a prompt message to the user and collect an input string that is returned back to the script.

An example of an input box appears in Figure 14.6. Unlike the message box, the input box has no icon that is displayed. It also does not provide any control over the buttons that appear. OK and Cancel buttons appear on every input box.

Figure 14.6 : The input box prompting for user input.

The input box gives you control over the most important aspects. Namely, you can retrieve text from it. The code that generated the input box in Figure 14.6 is shown in Listing 14.2.


Listing 14.2. The InputBox function call.
Sub cmdInputBox_OnClick
    dim strFeedback ' Feedback string
    dim rc ' return code from message box call
    rc = InputBox( _
        "Please provide the name of your favorite Visual Basic author." & _
         vbCrLf & vbCrLf &  _
        "You may enter more more than one name if desired." , _
        "Determining user preferences", "Brophy and Koets", 0, 0)

    strFeedback = "Response was " & rc & "." & vbCrLf
    if rc = "" then
         strFeedback = strFeedback & _
         "The user did not care to provide a response."
    elseif rc = "Brophy and Koets" then
         strFeedback = strFeedback & "The user used the default response."
    else
         strFeedback = strFeedback & _
         "The free thinking user supplied their own response."
    end if

    msgbox strFeedback, vbOKOnly, "InputBox User Response"
end sub

The InputBox function statement appears in the fourth statement of the listing. This is the function call format:

ResultVar = InputBox(prompt_message, optional_title,
optional_default_response, optional_x_position,
optional_y_position, optional_helpfile,
optional_helpfile_context
)

The first parameter is the prompt message. This is the message displayed in the input box window that prompts the user for his response. As you can see in Figure 14.6, the prompt for the sample is spread over more than one line. The vbCrLf declaration discussed earlier today can serve as a line separator for input box prompts, just as it can for message box prompts. The prompt must be supplied, but the rest of the parameters are optional.

The next parameter is the title of the window, which is displayed in the top caption area. If a title is not supplied, Visual Basic will appear in its place.

The third parameter is the default response. This response will show up in the text input area that is supplied for user input when the input box is generated. In the input box shown in Figure 14.6, Brophy and Koets was supplied as the default response. The default response is a response that the user is likely to provide. If he wants to go with the default, he can simply select the OK key and doesn't have to type in any text. To provide a specific response, the user simply types the desired response, then selects OK. The new input will automatically replace the highlighted default, and no backspacing or deletion is necessary.

The fourth and fifth parameters control the placement of the input box in x and y coordinates from the top of the screen. In the sample, the X and Y were specified to be 0, so the input box appeared at the top-left corner of the screen. If no values are supplied, the input box appears centered horizontally on the screen and a third of the way down. It is interesting to note that you cannot control the message box placement, but you can control the placement of the input box. You might want to control placement of an input box if you ask the user for information relating to what he has on the Web page in front of him. In that case, you don't want to obscure the user's view of the page any more than you have to in case he wants to rely on information on the page while deciding on his input.

The sixth and seventh parameters of the InputBox function call are for help file and help file context information. The help file support for InputBox is the same as that for the message box.

The manner of retrieving the user response for an InputBox call is also similar to that of MsgBox. After the user enters a string into the input area and clicks OK, that user-supplied value is returned. In the case of the example in Listing 14.2, the return value is assigned to the return code variable rc. From that point on, you can do anything with the variable that you would do with any string. The options are many, including comparing it, reassigning it, or searching it for a substring. If the user just selects OK without providing his own input, the default string will be returned. If there is no default, if the user deletes the text and presses OK, or if the user selects the Cancel button at any point, a zero-length string of "" will be returned. The code in Listing 14.2 illustrates how to check the return code to determine if a new string was provided, if the default string was used, or if a cancel occurred.

The InputBox function can extend the capabilities of your scripts very easily. The function is easy to use and integrate. Many languages provide similar functions. With traditional non-Web page applications, it might be considered bad form to rely too heavily on this function. A series of more detailed windows, or of good data collection on one dynamic window, often provides easier and better interaction for the user. However, in the scripted Web page model you are dealing with, your options are limited. It's not as easy to make the entire page dynamic since you often must share it with static HTML-generated text, and you can't provide the user with a series of windows controlled from one main script unless you resort to using more complex HTML frames. Often, the closest you can come is with controlled use of InputBox. This technique allows your scripts to make a page one step closer to an application and one step further away from being just a static display of information. At the end of this chapter a detailed example built on a flow of input boxes is provided. But first, consider one more interesting way to provide information to the user.

Documents

So far you've seen examples of many different ways to extend and control a Web page through your scripts. Integrated components such as input controls and ActiveX controls that can be manipulated through scripts were addressed on Day 10, "An Introduction to Objects and ActiveX Controls," and Day 11, "More ActiveX Controls." There are also capabilities for feedback that are intrinsic to VBScript such as the message box and input box functions examined today. But one area has not yet been approached. That is the Web page document itself and the HTML code on which it is based.

The document Object and the form Object

On earlier days, including Day 9, "More Intrinsic HTML Form Controls," you saw that a form is referenced with respect to the intrinsic document object. Suppose you have definitions like those in Listing 14.3.


Listing 14.3. An HTML definition to include a form on the page.
<FORM NAME="MyForm">
<INPUT NAME="txtAge">
<INPUT NAME="txtLastName">
</FORM>

A special means of designating these entities is needed if you want to reference that form and the text input controls on it through VBScript code. You must describe the controls in terms of the form object they are associated with, and the form object in terms of the page's document. To display the value of the input control in a message box, you would use code like the following:

MsgBox document.MyForm.txtLastName

document represents the page itself, and HTML forms are a part of that page. You don't have to worry too much about the document object in this context, other than to realize it is a part of the name you must use to reference a form control. There is even a VBScript shortcut to get you past using document in the reference every time. Just define a variable that refers to the document form, as in the following:

Set frmCurrent = document.MyForm

Then, in subsequent references to the txtLastName control you don't even have to include the document object:

MsgBox frmCurrent.txtLastName

The document.write Method

document can do a lot more than just give you a means to reference a form. To understand the additional capabilities, it helps to first consider what a document is and how it is generated. The Web page document is rendered by the browser based on the HTML instructions for the browser. The HTML tags are read in and interpreted when the page is loaded, and then are not processed again by the browser unless the document is reloaded by the user. Script options to control the document by generating HTML source code for the page are therefore limited. The easiest window of opportunity for a Web page script to affect the HTML behind a document is when the page is initially loaded.

Fortunately, an intrinsic document object is available for this purpose. document represents the page itself and has a write method that can be applied to the page. The document.write method can be used from code to write HTML statements to that page. Any valid HTML statement can be generated to the page by document.write. This method can be used to write to the page at load time if it is carried out by direct VBScript startup code when a page loads. The only way to have code launched as a page loads is to associate it with a script tag, but not within a specific procedure. The script in Listing 14.4, for example, would generate a heading that says Thanks for joining us at <current date and time>! as the page is loaded. The write method in the nonprocedure area of the code, shown in Listing 14.4, accomplishes this.


Listing 14.4. Using the document.write method as a page loads.
<HTML>
<HEAD>
<TITLE>Brophy & Koets' Teach Yourself VBScript - Document.Write Sample</TITLE>
</HEAD>
<BODY>
<H1>Weclome to this Web Page!</H1>
<SCRIPT LANGUAGE="VBScript">
       document.write "<H2>Thanks for joining us at " & now & "!<H2>"

</SCRIPT>
<p>This is a pretty short but cool web page. Notice it displays the time!
</BODY>

A page is rendered in sequential order of tags. That means the final result of the page in Listing 14.4 is a page in the browser that shows the title Welcome to this Web Page!, followed by the line Thanks for joining us..., followed by This is a pretty short but cool web page.... The resulting Web page is shown in Figure 14.7. If you moved the document.write statement to precede the <H1> tag, the Thanks for joining us... line would be at the top of the page.

Figure 14.7 : A Web page partially generated by document.write.

The HTML Body ONLOAD Event Procedure and Restrictions on Using document.write

If document.write appeared within an event procedure as a command button, the statement would not update the current page when the user selected that button. This is because document.write cannot append content to a page after the initial content drawing is complete. document.write can be used to build content but not to change it. This is even true of calls associated with the body tag ONLOAD attribute. You can specify a block of code that is called when your page loads by adding the appropriate language and ONLOAD attributes to the normal HTML body tag of your main script. For example, this statement specifies that a VBScript subroutine named Your_VBS_Subroutine will be called after the page is loaded:

<BODY language="VBScript" ONLOAD="Your_VBS_Subroutine">

Then at some point in your HTML page, you must have defined the procedure Your_VBS_Subroutine between <SCRIPT LANGUAGE="VBSCRIPT"> and </SCRIPT> tags. Any code in the procedure will get carried out as startup code, but it cannot use document.write to modify the current page.

Using document.write from VBScript at Page Load Time

The code in Listing 14.4 uses document.write successfully. That is because document.write is used within direct VBScript startup code. Direct VBScript startup code statements are those statements that are between the <SCRIPT> tags but not contained in a routine. This code is carried out whenever it is sequentially encountered as the page is loaded. document.write statements modify the page under construction in this context, and the resulting strings are just inserted after any preceding page content but before any page content lines not yet carried out.

On the other hand, a procedure that is designated by the ONLOAD event in the body tag is not called until after the page has been rendered. The whole page, including any direct VBScript startup code, will be sequentially drawn before this event is called. When the ONLOAD procedure finally gets its chance, it is too late to change the content of the page. document.write calls will have no effect on the current page at this point.

Note
The document.write behavior described here corresponds to the current official release of Internet Explorer andVBScript. Microsoft may change the document.write implementation to provide content append capabilities in future releases.

You can think of this in terms of the phases shown in Figure 14.8. There is a loading phase during which page source code is processed sequentially. HTML code is processed on the page in the order in which it is encountered. Any VBScript code encountered in the sequential flow will be carried out at this time as well, if it is not contained in procedures. This code can render HTML through document.write. However, this code cannot reference a control which has a definition further down in the page of source code because that definition is not yet in effect.

Figure 14.8 : The VBScript event time line.

The ONLOAD event occurs when the page generation is completed. If an ONLOAD event has been defined through the body tag, it will be carried out at this point. document.write can no longer be utilized to modify the current page because the page rendering is complete. However, because all control definitions are also complete, a control can be referenced.

After the completion of the ONLOAD event, the page is presented to the user. As the user interacts and causes events to occur, the associated event procedures will be carried out if they have been defined in script. The event code cannot use document.write to modify the current page because page rendering is complete. But because page definitions are complete, the event code can reference a control from anywhere. Listing 14.5 shows code with comments on each phase.


Listing 14.5. VBScript code for page rendering, on the load event, and at a user-initiated event.
<HTML>
<HEAD>
<TITLE>Brophy & Koets' Teach Yourself VBScript - Phase Sample</TITLE>
<SCRIPT LANGUAGE="VBScript">
<!--
sub MyOnLoad
' This procedure is called at load due to BODY ONLOAD attribute.

    ' Document.write cannot modify this page after it is rendered
    msgbox "MyOnLoad procedure cannot use " & _
       document.write to add to this page since page is already rendered!"

    ' Control can be modified even though its definition follows this code
    '      since page definition complete.
    cmdTest.Value = "MyOnLoad"
    msgbox "MyOnLoad procedure has modified control value."

end sub
-->
</SCRIPT>
</HEAD>

<!-- Use tag attribute to specify that a
VBScript procedure is carried out when page is loaded-->
<BODY LANGUAGE="VBScript" ONLOAD="MyOnLoad">
<H1>Weclome to this Web Page!</H1>
<SCRIPT LANGUAGE="VBScript">
<!--

' This is startup code. Since it is not in a procedure it is
' carried out when browser encounters it during page rendering.
document.write "<H2>Thanks for joining us at " & now & "!<H2>"
msgbox "Startup code has modified HTML content with document.write."

' Control cannot be modified since sequential page definition complete
'     still in progress and control not encountered yet.
msgbox "Startup code cannot modify control value since " & _
    " definition not in effect yet."


sub cmdTest_OnClick
' This event code is only processed when user clicks on cmdTest
'  button after page is loaded

    ' Document.write cannot modify this page after it is rendered
    msgbox "cmdTest_OnClick cannot use document.write to add to this page since Â" & _
       " page is already rendered!"

    ' Control can be modified even though its definition follows this code
    '    since page definition complete.
    cmdTest.Value = "cmdTest"
    msgbox "cmdTest_OnClick procedure has modified control value."

end sub
-->
</SCRIPT>
<p>This is a pretty short but cool web page.

<INPUT TYPE="Button" VALUE="Initial" NAME="cmdTest">

</BODY>
</HTML>

File phase.htm on the CD-ROM has code similar to that of Listing 14.5, but with more details as well. There is a block of code for each specific phase of the page life. The nonprocedure code is carried out as the page is rendered. The ONLOAD event occurs after the page loads. Then the event code is carried out in response to the user-initiated event. The comments in the listing indicate the legal actions at each phase.

Why Should You Use document.write?

The question of when to use document.write should now be quite clear. It can only be used in startup code or when you want to produce generate entirely new page contents. If you needed additional HTML statements, why not just put them in the original page of source code in the first place?

Generally speaking, you will want to put your HTML directly in the page to begin with. If you know what the starting view of the page should be and no load time factors should influence the page's appearance, you have no need for document.write. On the other hand, there are several reasons you might wish to add HTML to a page through code as it is loaded.

The first reason is illustrated in Listing 14.4. With document.write you can easily insert a date, time, day of week, or other information into the page. Perhaps you want the date at the top of a page that serves as a report. You don't want to have to write server-side page generation code to do this because you can place pages on your provider's server but cannot place CGI scripts there. You'd use document.write to insert the date on each page as it is loaded, as shown in Listing 14.4. The smarts to carry out this dynamic customization are embedded right in the page itself rather than in a server application.

Another reason you may wish to use document.write is that in some cases it may be easier to generate information on a page through a code loop than to write out all the HTML statements directly. Suppose you wanted to create a page that listed multiples of 17 between 0 and 100,000. Perhaps this is to provide a check sheet or counter sheet for inventory control, where the shipments will occur in lots of 17. It would take an enormous amount of time to create this page by typing it; you'd have to type more than 5000 numbers. But with document.write, you just type a few lines of code (see Listing 14.6).


Listing 14.6. Using a code loop and document.write to avoid typing in many lines of code.
<HTML>
<HEAD>
<TITLE>Brophy & Koets' Teach Yourself VBScript
 - Inventory Count Sheet Sample</TITLE>
<SCRIPT LANGUAGE=VBS>
<!--

' This is startup code. Since it is not in
' a procedure it is carried out when browser encounters it during page rendering.
document.write "<H2>Counter sheet for inventory on " & now & "<H2>"
dim lngLoopCount

do while  lngLoopCount < 100000
    document.write "<p>Lot Number " & loop
    lngLoopCount = lngLoopCount + 17
loop
-->
</SCRIPT>
</BODY>
</HTML>

The startup code in Listing 14.6 has the same end result as if you wrote the page with all 5000+ lines. Unless you are specifically seeking finger exercise, the document.write approach is clearly desirable! As an added bonus, the page based on the VBScript document.write approach will be quicker to download from the server since it contains fewer lines of code.

So any page that could make use of a loop to generate repeated patterns of tags and content is a candidate for a document.write approach. Likewise, pages that display the results of repeated calculations, such as a trig table, can lend themselves to this approach. Such pages are not the norm, but if you create enough, you are likely to come across such a candidate eventually.

Another reason to use document.write is that it lets you dynamically create a new page, without requiring an actual page on the server. You can cut down the number of page files to manage and create pages that have dynamically responded to conditions of the previous page.

The final type of page to consider for a document.write approach is one where you give the user the choice of page presentation as the page loads. You can do this with the message box or input statements covered earlier. This can make for a very user-customizable page without requiring any server code.

For example, assume you want to supply a kid's activity planner. You want to provide slightly different customization and feedback, depending on whether the user wants to activities to cost money. However, you believe the basic design of the pages is similar enough that you want to just implement this solution on one page. That way, you'll just have one page to store and maintain for the future.

You could involve the server to help produce a custom page, but in this case, it is unnecessary. Server code takes more debugging, requires server script creation access, and will mean more network traffic for your user. On the other hand, VBScript code allows all customization to be embedded right in your page. In other words, you craft your own script customization.

For the kid's activity planner example, the first step of customization is to find out if the user wants to spend money on the activities. You use a message box in the script startup code to prompt the user for his response as soon as the page starts to load. This code is shown in Listing 14.7.


Listing 14.7. Find out the user preferences as the page loads.
<HTML>
<HEAD>
<TITLE>Brophy & Koets' Teach Yourself VBScript - Dynamic Page Sample</TITLE>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="VBScript">

    dim rc           ' Stores return code value
    dim Spender      ' True if user says they don't mind spending money
    rc = msgbox("Are you willing to spend some bucks if needed?", _
         vbYesNo + vbQuestion,"Setting up the Kid's Rainy Day Activity Planner")
    if rc = vbYes then

       ' Show Big Spender Page
        Spender = vbTrue

       document.write "<H2><A HREF=""http://www.mcp.com"">"
       document.write _
        ""<IMG  ALIGN=BOTTOM SRC=""../shared/jpg/samsnet.jpg"" BORDER=2></A>"
       document.write  _
         "<EM>Kid's Activity Planner for the Big Spender</EM></h2>"
       document.write "<HR>"
       document.write "<p>Activities that cost, but keep them happy!"
       document.write "<UL>"
       document.write _
         "<LI>Let them go on a shopping spree in the local toy store."
       document.write "<LI>Take them to a movie."
       document.write "<LI>Buy them a new bike, but let them put it together."
       document.write "</UL>"
    else
       ' Show Cheapskate Page
       Spender = vbFalse
       document.write "<H2><A HREF=""http://www.mcp.com"">"
       document.write _
         "<IMG  ALIGN=BOTTOM SRC=""../shared/jpg/samsnet.jpg"" BORDER=2></A>"
       document.write "<EM>Kid's Activity Planner on a Budget</EM></h2>"
       document.write "<HR>"
       document.write "<p>Activities that won't cost you a dime!"
       document.write "<UL>"
       document.write "<LI>Send them to the neighbors to play."
       document.write "<LI>Tell them you lost your wallet in the backyard " & _
            " and half of the money in it is theirs if they find it for you."
        document.write "<LI>Show them how to play Solitaire on the computer."
        document.write "</UL>"
    end if
</SCRIPT>
</BODY>
</HTML>

The block of code in Listing 14.7 will be carried out as the page starts to load because it is not contained in a procedure. The code's first action will be to ask the user via a message box if he wants to spend money. This message box is shown in Figure 14.9.

Figure 14.9 : Prompting for user preferences at page load time.

The return code with the user's response to the message box is evaluated next. If the return code indicates that the user wants to spend money, one set of HTML tags is generated with document.write with content directed at those users who are willing to spend money. Otherwise, document.write generates a different set of HTML tags targeted at the cheapskate crowd.

You have a user-customized page! But if this were all that was involved, you might as well have just created two separate pages in the first place. However, assume there is still more information that you want to show on every page, regardless of the user's attitude toward money. An additional list of generic activities is provided in either case, along with a helper button. This common HTML can be generated just once, following the customized section. The portion of the page that generates this generic information is regular HTML (with no script needed) and is shown in Listing 14.8.


Listing 14.8. Planner.htm generic information.
<HR>

<p>Here are some more ideas to consider:
<UL>
<LI>Play duck-duck-goose. Have a rule that the goosed must go
around the circle <EM>300</EM> times before sitting.
<LI>Ask the kids to draw a picture of the universe.
<LI>Provide a box of toothpicks and have them figure out the dimensions
of each room of the house in terms of the toothpicks.
</UL>

<HR>
<FORM NAME="frmAdvice">
<p>Chester the cat, an expert on kids, can
provide more suggestions based on an analysis
of your situation. Select <em>Advice from Chester</em> if you'd like his help.
<br>
<br>
<center>
<INPUT TYPE=BUTTON VALUE="Advice from Chester" SIZE=30 NAME="ChestersAdvice">
</center>
</FORM>

Note
Source code for this page, called Planner.htm, is available on the CD-ROM.

The fact that this block appears only once in Listing 14.8 highlights the first clear benefit of the customized page. VBScript lets you generate multiple lead-in sections for the same page. You have just one Web page to maintain and update. The advantages of this approach may seem slight, since just a couple pages would be required to implement a traditional solution with this specific example. But if you amplify the situation to consider the case of many customizations and lines of generic code that follow, the avoided redundant pages become greater incentive for using this technique.

After the user indicates his preference regarding spending money on activities, a page like the one shown in Figure 14.10 is displayed. If the user had indicated he didn't want to spend money, he would have been presented with the same page, but with a different customization, which is shown in Figure 14.11.

Figure 14.10 : The page customized for big spenders.

Figure 14.11 : The same page customized for cheapskates.

The dynamic interaction offered by this page can go even further. At the bottom of the page is a button the user can select if he wants even more ideas that are derived in a question and answer session. The code behind this button will provide a series of questions to the user through message boxes and input boxes. Based on the user's responses, a highly customized activity recommendation will be produced. The final recommendation will be displayed to the user through an input box (as shown in the sample). It also could have been displayed directly on the page through other means, such as a label, a text box, or another control.

This sample program shows a highly interactive page that is customized based on user preferences when it is loaded. Then, in response to a request for further information, the user can access a detailed set of questions designed to glean more information from the user. After the user supplies the answers, an additional recommendation can be provided based on this information. All this is done with the same page and controlled by easily maintained code within that page.

There is a lot more you can do with the document object. You can write information after a page is loaded. You simply use document.close to make your changes take effect after a document.write. This will cause the page to be generated again, but will wipe out your old contents! Intrinsic browser objects like the document object will be discussed in more detail on Day 18.

Summary

Today's lesson looks at how you can make dynamic documents through intrinsic functions of VBScript and the document object rather than through separate components of the page. The message box function MsgBox provides feedback to the user in a message window. The message remains for the user until it is acknowledged. The Alert function serves the same purpose, but places the title Alert at the top of the window. Parameters of the MsgBox function control the message, title, icon, and buttons displayed. This function can even be used to solicit a response from the user. If more than one button has been requested, the function returns an indication of which button was selected.

The MsgBox function goes a long way toward creating interactive pages without integrating components, but a closely related function goes even further: the InputBox function. The InputBox function works like the message box function in many respects. Parameters control a prompt message and title. In addition, parameters can indicate where the input window should be positioned onscreen. The most important distinguishing characteristic of InputBox, however, is that it uses the prompt message to prompt the user for an input string. That input string is then returned to your script.

There is yet another way to communicate from scripts without integrating components. This is through the intrinsic document object and its document.write property. Your scripts can generate their own HTML statements on the page. For example, a script can tell the browser to place the title Heading 2 at the top of the page; you simply enclose the text Heading 2 in <H2> and </H2> tags. Or a script can generate an ordered list. Essentially, anything that can be done through HTML tags can be generated by your script directly to the document. However, the document.write method can only modify the current page at form load time. The page is generated sequentially, so if any normal HTML tags appear in the HTML file prior to the script that references document.write, those tags will precede the ones generated by the script.

Some ideas of where you can use document.write are discussed in today's lesson. These include a look at the VBScript event time line. VBScript startup code is the only place you can use document.write. An additional approach for defining code carried out as the page loads through the use of the <BODY> tag and ONLOAD attribute is provided, but document.write cannot be used from this event or from normal control events to change the current page. The reasons for this are outlined, as are considerations of accessing controls in each of these different phases of code execution. One or more document.writes can be used at any time if they are followed by a document.close, but that will result in the replacement of the old contents of your page by whatever you wrote.

After providing a discussion of dynamic interaction and document generation, this lesson provides an example that uses the techniques discussed. A Web page with dynamically generated content based on a user's response to a prompt during the page load operation is illustrated. This page also has the capability to initiate an extensive series of questions for user response, and can display new results at the end of the series of questions.

All this interaction takes place on the same Web page, with no server intervention required. You can use VBScript in this manner to easily make truly interactive Web pages. As the lesson shows, VBScript is not only the glue that lets you control the components in your pages, it is also the framework for user interaction.

Q&A

QCan you use document.write to modify a Web page in response to the user clicking on an intrinsic command button or label control?
ANo. document.write can only be used to modify the current page at page load time. Since Click events on controls can occur only after the page is loaded, document.write will not work in that event code.
QHow can you supply a default response for the user when you use the InputBox function to prompt for input?
AResponse = InputBox ("What gift would you like to select " & _
" for that lovely couple Marco and Terri for their wedding?", _
"Please select a gift", "Gold-plated electric banjo")
The user will see Gold-plated electric banjo in the input area as soon as InputBox is displayed. He can press Enter to accept this response or type over it with his own response.

Workshop

Generally, there is more than one approach for providing user feedback. Determining which approach is best is a subjective matter. For example, suppose you want to write a Web page that lets the user provide three bowling scores. Then, when the user clicks on a Calculate button, your Web page provides the average.

If the user enters a score greater than 300 for one game, you need to provide an error message. After all, 300 is the highest score possible, so your user either made a mistake or is trying to fib to the program! You could provide the error feedback in several different ways. Your script could pop up a message box calling the user's attention to the error. Or it could display the error message in a label that had been previously blank on the Web page. Or the script could generate the error right to the label or text box where the final average would normally appear.

Implement three different Web pages for the bowling average score program. Make the pages identical except for the error feedback. Then interact with all three pages, forcing the error. Decide which method you think provides the best user feedback. Although you can always find an opinionated programmer to tell you his way is the only way, there is no universal programmer's rule that dictates which approach you must use in such cases. Most pages implement the message box approach because it easily catches the user's attention, demands a response that ensures the user has seen it, and is easy to implement. Do you agree this is the best approach after trying all three methods?

Quiz

Note
Refer to Appendix C, "Answers to Quiz Questions," for the answers to these questions.

  1. Provide code that asks the user if he wants to see extra hints when a page is loaded. If the user responds affirmatively, have the code write the heading Extra Hints at the top of the page.
  2. Use your answer to the first quiz question as the basis for this solution. Take that code and modify it so that Extra Hints appears between the question and answer sections (between the two <BR> lines) when the user responds affirmatively to the prompt.
  3. If you supply Yes, No, and Cancel buttons on a message box, one of the buttons will be highlighted and the user can select it by pressing Enter (or the space bar, in Windows 95). Show the code that will highlight the No button, which is the middle of the three buttons that appear on the message box. Use anything for the message and title content.