Digital Media

Moshell - Spring 98

Lecture 15: Flow Control with Multiple Forms
and
G Chapter 8
Multiple Form Interaction
We will first discuss the problem of

* Flow Control with Multiple Forms

Then we look at G chapter 8, which covers several items:
 
* Hidden fields
* CGI Side Includes

Flow Control

In the lecture I will draw a three column flow chart for a simple answer-and-error-check application, similar to your Lab 2. We will consider the question of how the script knows which version of the form to emit, and how the user moves through the process. I don't have a quick and easy way to draw pictures and put them here in the notes, but will try to get one!

Now for G Chapter 8.

It helps if we first agree that we'll have a big associative array named $FORM. Every data field in any form we're going to use, will have a name and a value. Let's establish a convention that all data field's names begin with df. Thus, the firstname field in Form 1 would be named df_firstname. In FORM, we would store its value in $FORM{"df_firstname"}, and in the input stream, we would see df_firstname=Michael (if I had put Michael into that field of the form.)

I don't like to use $STATE, as the text does, because that falsely suggests that this array can preserve the state of your work between sessions. We must preserve the state, on all occasions, either by sending it back out to the user, or by keeping it in a database using the "cookie" technique which we'll discuss later.

CGI Side Includes are cases where you put a special marker into your "Master file" and design your CGI script to replace the markers with dynamic information. How does this differ from a Server Side Include, like in Chapter 5?

SSI examples, to remind you how it works:

<!--#echo var="LAST_MODIFIED"-->

This looks like an HTML comment because it begins with <!, but the browser knows to pass the string after the # and up to the --, right through to Unix to be processed. No script is required. You can even ask a script to run, with this command:

<!--#exec cgi="/cgi-bin/counter.pl"-->

But this technique is very limited. A script so executed can't put out anything but text, because it's in the middle of an HTML data file already. And it's hard to maintain the state of a given transaction. This is called the Persistence Problem.

The Persistence Problem Discussed. Pretend you're a European school-teacher, trying to manage 25 kids on a field trip to a neighboring country. They are too young to take care of all their paperwork(passport, visas, money, etc.). So you have two choices: you can tie a string around each child's neck and put the papers in a bag, which you then tuck inside the kid's shirt. Or you can take out your magic marker and write on the kid's head, a bright green number. Then you keep a file box with numbered folders, holding each kid's individual information.

The first method (packets inside the kids' shirts) represents the use of hidden fields. The second method (numbering the kids and keeping a database) represents the "cookie" method. Both of these are physically realized via CGI Side Includes, which we will now discuss. <<You can't give the schoolkids cookies with special numbers on the front; they'd eat them!>>

CGI Side Includes (CSI) are managed by special tags that you put into the HTML of your Master Document. This gives you much more control than Server Side Includes would give.

In the text, the author uses tags which look just like HTML, such as

<!--#insert var="DATE_TIME"-->

which looks like a server side include. The advantage of such a technique is that you can look at the Master Document with your browser, and you will simply see nothing where your dynamic data was supposed to appear. The disadvantage is that the tags look too much like something else.

In the in-class example, I asked you to design code which would look for tags that we made up, which began with the tilde character. Today we're using a slightly different convention:

~~tagname~~

would be replaced by $STATE{"tagname"}

Let's now consider two issues, based on this technique:

1) Choosing the next form to display: Flow Control and Defaults
2) Recycling forms when errors are detected

We will address all these problems by designing a simple application.

The Shrink Support System (SSS)

Consider the following multi-form problem. Your client is a psychologist, who wants to administer a test containing ten binary-choice questions (as well as fields for the student's first and last names, and student ID numbers.). A typical question might be

"Which color do you prefer? Check one:"

o   Brown
o   Purple

At the bottom of the form is a submit button. If the user clicks on SUBMIT before they have specified choices on all ten questions, the program must display a screen which itemizes which questions haven't been answered, and presents a CONTINUE button. When that one is clicked, the original form comes back up - with any information which you originally entered, still there!
 

This task generates two interesting problems.

Problem 1: How can you write a script which kicks out a replacement form on the second and subsequent passes, which contains such information as the user has filled in already?
 
Problem 2: In order to prevent bias, each of the ten questions must have its choices presented in random order - that is, half the users will get Brown first, and half will get Purple first. Now obviously you could make up multiple questionnaires to solve this problem, but equally obviously, you'd need 2**10 = 1024 forms. That's a bit tedious.

We'll work on these problems in class, and develop a consensus answer. Here is the relevant information for attacking Problem 1:

<INPUT TYPE="radio" NAME="q1" VALUE="1" CHECKED> Brown <BR>
<INPUT TYPE="radio" NAME="q1" VALUE="2"> Purple <BR>

 This configuration would cause the two buttons to be displayed, with the initial display showing the Brown button checked.

Don't look at the following hint until you've thought about the problem and attempted to design a solution for yourself!

***************
***************
***************
***************
***************
***************
* OK, you lazy rascals. Here's a hint:
***************
***************

HINT: You need to have your server prepare a special variable, perhaps named $FILLIN{"check_q1v1"}
and containing the string value "CHECKED" just in case variable q1 has value q1v1. Otherwise it's empty. Now - what do you do with this special variable?

Don't look at the following hint until you've thought about the problem and attempted to design a solution for yourself!

***************
***************
***************
***************
***************
***************
* OK again, you lazy rascals. Here's a hint:
***************
***************
 
    if ($FORM{"q1"})
     {
        $key = "check_q1v".$FORM{"q1"};
        $FILLIN{$key}="CHECKED";
    }

Now all you have to do, is to figure out how to make that code work for q1 up through q10, without writing it ten times. The challenge is always to make your script as generic as possible (able to be used with many different Master Forms, with no customization, or at most a little bit of customization.

Problem 2: Randomizing the Questions. Now, how would you go about developing a CSI solution to the randomizing of the questions? It begins to look like the whole form is going to disappear into the script, and there won't be anything to see in the Master Form.

Consider this augmented HTML:

~#randomize
<INPUT TYPE="radio" NAME="q1" VALUE="1" >Brown ~~q1v1~~<BR>
~#
<INPUT TYPE="radio" NAME="q1" VALUE="2"> Purple ~~q1v2~~<BR>
~#endRandomize

Now, can you think up a strategy which would allow your CGI script to emit a questionnaire which had radio button groups in random order, different every time?

What new problems would this technique cause? How would you solve them?

The above example shows how powerful CSI techniques can be, in building a truly dynamic web site.