Internet Technologies:waa

The address form Professional

The first selection in the menu page leads to the Address Entry Form where a potential customer can enter address data and submit the form. This is a common task of Web applications and requires two form-functions: the first sends an HTML page to a Web browser presenting input controls to the user, and the second receives input data and stores it in a database on the server side. The two functions EnterAddress() and SaveAddress()serve this purpose in the Klondike Computer Shop example and are programmed in the file ADDRESS.PRG. Let us start with looking at EnterAddress():

01: FUNCTION EnterAddress( oHTML, oContext ) 
02:    OpenCustomerDbf()
03:    KlondikeHeader( oHtml )
04: 
05:    oHtml:formStart() 
06: 
07:    oHtml:put( '<H3><B>Please enter your complete address:</B></H3>' ) 
08: 
09:    BuildAddressTable( oHtml, oContext )
10: 
11:    oHtml:put( '<BR>' ) 
12: 
13:    oHtml:setVar( "WAA_PACKAGE", "Klondike"    ) 
14:    oHtml:setVar( "WAA_FORM"   , "SaveAddress" ) 
15:    oHtml:submitButton( "Send Address" ) 
16: 
17:    oHtml:formEnd() 
18: 
19:    KlondikeFooter( oHtml )
20:    CloseCustomerDbf() 
21: RETURN .T. 

The code starts with opening a Customer database which is encapsulated in the user-defined function OpenCustomerDbf(). This function simply checks for the existence of CUSTOMER.DBF and CUSTOMER.CDX and creates these files if missing. The HTML code creation starts inKlondikeHeader()which is a wrapper function for the oHtml:header() method call. This way, a uniform head line can be created easily for all HTML pages of the Klondike Computer Store (KlondikeHeader() and KlondikeFooter() are programmed in KLONDIKE.PRG). If the head line needs to be changed, there is only one place to adapt PRG code.

The form definition between :formStart() and :formEnd() includes the required submit button in line #15 which invokes the SaveAddress()function when the user has entered address data. The HTML code for the corresponding input controls is created by the procedure BuildAddressTable()in line #9 whose code follows:

01: PROCEDURE BuildAddressTable( oHtml, oContext ) 
02: 
03:    <... position record pointer ...> 
04: 
05:    oHtml:put( '<TABLE WIDTH="80%" BORDER=0 BGCOLOR="#CCCCCC">' ) 
06: 
07:    oHtml:put( '<TR><TD>' ) 
08:    oHtml:SLE( 'First Name:' , 'F_FIRSTNAME', Trim( Cust->FIRSTNAME ) )
09: 
10:    oHtml:put( '</TD><TD>' ) 
11:    oHtml:SLE( 'Last Name:'  , 'F_LASTNAME' , Trim( Cust->LASTNAME  ) )
12: 
13:    <... rest of input controls ...> 
14: 
15:    oHtml:put( '</TD></TR></TABLE>' ) 
16: RETURN 

Single line edit controls are created for the different database fields of CUSTOMER.DBF using the oHtml:SLE() method in line #8 and #11. This method builds the HTML code for SLEs, including caption, variable name and initial value for the SLE's edit buffer (parameters 1-3). The latter is taken from the database if a user has visited this HTML page already. However, this is discussed later when we look at session management since we have to finish the discussion of the Edit/Save cycle first. Just keep in mind that the record pointer of CUSTOMER.DBF is moved to an existing record in line #3 or ends up at the ghost record so that the SLEs are initialized with empty data.

All input controls are arranged in the HTML page in tabular form, and the HTML code for the table is added with the :put() method. The procedure returns when the table is completely defined. This means that the only task of procedure BuildAddressTable() is to create the HTML code for one complex control, the address entry table, consisting of well arranged standard input controls. Since no other HTML code is created in this procedure, like header, footer or text, for example, it can be re-used in the definition of other HTML pages, and that is the reason why the code is isolated from the form-function EnterAddress() (as a matter of fact, the address table is used in two HTML pages of the Klondike Computer Shop).

When a user has filled in address data in a Web browser and submits the form, entered data is processed in the SaveAddress() function which starts with validating retrieved data:

01: FUNCTION SaveAddress( oHTML, oContext ) 
02:    LOCAL cLastName  := oHtml:getVar( "F_LASTNAME"  ) 
03:    LOCAL cFirstName := oHtml:getVar( "F_FIRSTNAME" ) 
04:    LOCAL cEmail     := oHtml:getVar( "F_EMAIL"     ) 
05:    <...> 
06:    
07:    IF Empty( cLastName ) .OR. Empty( cFirstName ) .OR. Empty( cEmail ) 
08:       oHtml:message( "Missing data", ; 
09:             "Please fill First Name, Last Name and EMail address." ) 
10:       RETURN .T. 
11:    ENDIF 
12: 
13:    cSeek := Upper( PadR( cLastName , 30 ) + ; 
14:                    PadR( cFirstName, 30 ) + ; 
15:                    PadR( cEmail    , 40 )   ) 
16: 
17:    OpenCustomerDbf() 
18: 
19:    IF ! DbSeek( cSeek ) 
20:       APPEND BLANK 
21:    ENDIF 
22:    
23:    IF ! Rlock() 
24:       CloseCustomerDbf() 
25:       oHtml:message( "Unavailable file", ; 
26:             "Sorry, your data cannot be processed at the moment." ) 
27:       RETURN .T. 
28:    ENDIF 
29: 
30:    REPLACE Cust->FIRSTNAME WITH oHtml:getVar( "F_FIRSTNAME" )  
31:    REPLACE Cust->LASTNAME  WITH oHtml:getVar( "F_LASTNAME"  )  
32: 
33:    <...> 
34: 
35:    CloseCustomerDbf() 
36: 
37: RETURN ViewShowRoom( oHtml, oContext, ... ) 

Edited data is retrieved from input controls by passing the variable name attached to the control to the :getVar() method (lines #2-4). It returns the edited value as a string. Since HTML controls do not support any kind of data validation, it is the Web application's responsibility to verify data submitted from a Web browser. This example tests for three "must fill" input fields and returns a message if one is left empty. Note the RETURN .T. statement in line #10. It must follow immediately after the :message() call and no other method of the HTML3 object may be called after :message().

The example program uses first name, last name and e-mail address as unique identifier for a potential customer and adds a new record to the database if this data is not found (line #20). Since the database is opened in shared mode, the record must be locked before data is finally written into the database. When this is done, the function returns an HTML page which is created in anothter form-function and presents the "showroom" of the Klondike Computer Shop.

When your Web application allows for data input in a Web browser, it must use at least two form-functions. One creates the HTML page with input controls and the other stores received data in a database. For this, you must open the database in shared mode because your Web application can be accessed simultaneously as many times as you have dimensioned the pool of worker threads for the WAA server (refer to the configuration of the WAA server).

Feedback

If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.