A Simple Web Application
by Michael Nuwer

This article was written for Visual dBASE 7.01. Significant changes have been made to the dBASE product line, particularly with respect to Web applications. For this reason the code used in this article may not be useful to the reader. However, the general conceptual framework regarding Data Modifications and Application Flow are still valid. — Michael Nuwer (October 2002)

T his essay is intended to explore issues related to developing a dBASE application for the Internet. It is not my intent to repeat materials that have been explored in Web.How by Alan Katz, nor to repeat procedures demonstrated in the web wizards which are included with Visual dBASE 7.0. In this essay I intend to take a small step beyond these two resources by first, showing how a simple dBASE web application can be developed and, second, showing how to edit dBASE data from a web form. The sample application used for this essay can be obtained here.

I teach at a small college in the United States where I use an application similar to this sample on my Class web site. The application collects information about the students enrolled in the class. I require that each student enter their name, student ID number, email address, campus username, and a password. With this information in a database table, I create web server login accounts, file upload folders, an online grade book, a class listserve, and customized project files.

After reading the Web.How paper and with the help of the Web Wizards, creating a web-based data entry form was a breeze. Most of my students, however, are 18-year-old freshmen (i.e., first year of college in the US) and they tend to submit inaccurate information. First I tried to validate the data that the students entered with JavaScript in the web form, but there were still many inaccuracies. So I needed a way to let the student modify the information they had entered.

About eighteen-month ago, when I ran an application like this on the College LAN, modifying records was simply a mode of the rowset. However, this is not the same with a web application. After a web application finds the data to modify, it prints a web page containing that data, and, then, the application is suspended. The data table is closed when the web user is viewing the data as a web form. Thus, to modify a record, I needed two procedures: One to seek the record to modify and “paint” the web page, a second to receive the modified data, find the correct record in the data table, and update the record.

My application needed three sub-procedures: one to add new data, a second to find data for modification, and a third to update the data. I did not want to create a separate executable for each of these sub-procedures so I needed a way for the web forms to control the application. To do this, my dBASE application uses a Case statement to evaluate commands from the web forms.

I will now discuss these two issues.

Modify Data

The basic steps to modify a record are as follows:

1. Find the record in the data table.
2. Print a web page that contains the fields to be edited.
3. Include a unique record identifier that can not be edited.
4. Send the web page to the browser.
5. Receive the updated data from the web browser.
6. Find the record in the data table again.
7. Update the record.

My table of student information is indexed on username and record ID. The latter is an AutoIncrement field used to control updating the data. Both fields must be unique, but students are permitted to modify their username. This is a peculiarity to my circumstance and may not be useful or necessary in other applications. Nevertheless, when a student makes a request to modify their information, the application seeks the username. If the username is found, the application prints an HTML page for modifying the record. The dBASE code for one field looks like this:

| `01 fOut.Puts([<TD BGCOLOR="#009999"><B>Last Name:</B></TD>])` `02 fOut.Puts([<TD BGCOLOR="#009999"><INPUT TYPE=TEXT NAME="Lname"])` `03 If not empty(data->lname)` `04 fOut.Puts([VALUE="] + trim(data->lname) + ["])` `05 Endif` `06 fOut.Puts([></TD>])`

The first line prints the HTML for the field label in a table’s cell. The second line prints the beginning of the HTML input tag. If there is data in the field, line four prints the value of the input. Line six closes the HTML input tag and ends the table cell. In the web page these lines will look as follows:

| `<TD BGCOLOR="#009999"><B>Last Name:</B></TD>` `<TD BGCOLOR="#009999"><INPUT TYPE=TEXT NAME="Lname" VALUE="Nuwer"></TD>`

When the modified data is returned to the web server, the application must be able to find the record that was modified. For this reason I include a hidden field in the modify page which contains the value of the AutoIncrement field.

| `fOut.Puts([<INPUT TYPE="hidden" NAME="ID" VALUE="] ;` `+ str(data->ID,3,0) + [">])`

In the web page these lines will look as follows:

| `<INPUT TYPE="hidden" NAME="ID" VALUE=" 14">`

When the browser submits the web form, the dBASE application seeks this value in the data table. The important point here is that there must be at least one field in the table that users can not modify. Otherwise there will be no way to know which record needs to be updated.

Controlling Application Flow

My simple application includes three primary procedures. Each procedure could be compiled separately and the web forms could call the requisite executable. I find it simpler, however, to create one executable and let the program branch with a Case statement.

In order to control the application from a web browser, all the submit buttons in the web forms are named “action”. For example, the HTML for the two buttons on the modify record page looks like this:

| `<INPUT TYPE=SUBMIT NAME=action VALUE="Modify This Record">` `<INPUT TYPE=SUBMIT NAME=action VALUE="Abandon Changes">`

When the user clicks the button titled Modify This Record, the CGI query_string includes the name/value pair: action= Modify This Record. In my application this name/value pair is always the last pair in the query_string. (This is controlled by the order of the <INPUT> tags within the <FORM> tag.) The last name/value pair is stored to the memory variable called cAction when my dBASE application receives the CGI query_string.

Custom buttons could be used as an alternative method of submitting web forms. An explanation of how to use custom command buttons is available `here` .

There are four values of cAction that my application is looking for
Add -> this will generate a web page for data entry.
Add Record -> data passed from the data entry page is appended to the data table
Modify Record -> This will generate a web page that is populated with data from our table.
Modify This Record -> Data passed from the modify page replaces the existing data in the table.

Since the dBASE developer is now on familiar ground I will simply explain what each case does in my simple application.

| `Do Case` `Case (ltrim(trim(cAction)) == "Add")`

Print the add-a-new-record web page. This page has the action button with the value of “Add Record”

| `Case (cAction == "Add Record")`

If the username does not already exist, append a blank record to the table and update the fields with the data passed from the web form. After the record is added the default page is printed to the web browser.

| `Case (cAction == "Modify Record")`

The default web page passes a username to the application, which then seeks the record. If the username is in the data table, the application will print the modify data page. This page sends the table data to the browser for the user to update. The Modify Record page has the action button with a value of “Modify This Record” and it includes the hidden record ID field.

| `Case (cAction == "Modify This Record")`

The web form sends the record ID field back to the application. The application seeks this record ID so as to return to the correct record. If it is found, the record is updated with the data from the CGI. Finally the default web page is printed.

| `Otherwise`

Print the default (or initial) web page. This will occur if cAction is empty or if it is equal to one of the escape phrases. For example, on the Modify Record form the button that reads Abandon Changes will cause this case to occur.

Closing Comments

The simple dBASE application that I’ve discussed here can be modified and/or expanded to do many different things. I hope that this discussion helps cut away some of the mystery of web application. For more information, I encourage you read Alan Katz’s Web.How paper and to create a few applications with the web wizards. (Be sure to get the newest version at `http://www.dbase.com/Docs/Downloads.htm`) Read the PRG file that is created by the web wizards, because there’s a lot of good stuff in those programs. Finally, if you would like to look at a few more web sample, I have posted some at `http://www.nuwermj.potsdam.edu/dSamples/`.

Michael Nuwer is Associate Professor of Economics at the State University of New York at Potsdam. He is also a part-time database consultant in the local community.