WebSpeed
Developer’s Guide


Complex HTML Mapping That Includes a SmartDataObject

Figure 4–7 shows the Web page generated by another sample WebSpeed application, w-custdir.w.

Figure 4–7: Web Page Generated from w-custdir.w

The Web page shown in Figure 4–7 interacts with the Customer table of the Sports2000 database like the other examples in this section. However, it also has the ability to add or change records in the table. Moreover, it uses a SmartDataObject to define its query logic. The following sections describe these features in more detail.

Creating a SmartDataObject

SmartDataObjects provide query logic that is separate from the rest of your application. As separate modules, they can be used by multiple applications, can be refined at run time, and can be modified more easily than queries that are embedded within applications. Another advantage to SmartDataObjects is that they can be used on an AppServer for multi-tier deployment. See Building Distributed Applications Using the Progress AppServer for more information.

SmartDataObjects can easily be created in the AppBuilder. The SmartDataObject associated with w-custdir.w is called dcustomer.w. You can create it by performing the following steps:

  1. Choose File New from the AppBuilder main menu.
  2. The New Object dialog box appears:

  3. Select SmartDataObject from the list of SmartObjects.
  4. Note that AppBuilder must be connected to a database in order to create a SmartDataObject. The procedures for starting and connecting to a database are described in Getting Started with WebSpeed .

  5. Choose Next on the SmartDataObject Wizard, then choose Define Query from page 2 of the wizard.
  6. In the Query Builder:
    1. Add the Customer table to the Select Tables list.
    2. Select the Sort button.
    3. Add Name to the Selected Fields list.
  7. Go to the next dialog box in the wizard (page 4) and choose Add Fields.
  8. Choose Add and add all of the available fields to the Selected Fields list.
  9. Go to the final page of the wizard and choose Finish.
  10. You will see a window labeled Untitled, which represents the SmartDataObject you just created. You can save it as dcustomer.w from the File menu of the AppBuilder.

When you save a SmartDataObject, you create a number of files: .w, .r, _cl.w, _cl.r, and .i. For more information about the function of these files, or for more information about SmartDataObjects in general, see the Progress ADM 2 Guide and the Progress ADM 2 Reference.

For more information about creating SmartDataObjects with the AppBuilder, see the Progress AppBuilder Developer’s Guide.

Mapping With a SmartDataObject

You can specify dcustomer.w as the data source when you use the HTML Mapping Wizard to map an HTML file like w-custdir.htm:

w-custdir.htm 
<html>
<head>
<title>Sample of Using HTML Mapping with an SDO</title>
</head>
<h3><font color="#000000">Customer Directory</font></h3>
<form ACTION="w-custdir.w" METHOD="POST">
<input type="hidden" name="cusrowid" >
<input type="hidden" name="AddMode" >
<pre>
<input NAME="SearchName" SIZE="20">
<input TYPE="submit" NAME="requestedAction" VALUE="Search for Name">
Name :  <input NAME="Name" SIZE="34"> 
Address: <input NAME="Address" SIZE="34">
        <input NAME="City" SIZE="12">
        <input NAME="State" SIZE="20">
        <input NAME="PostalCode" SIZE="10">
Phone:  <input NAME="Phone" SIZE="20">
Email:  <input NAME="EmailAddress" SIZE="20"> 
Fax:    <input NAME="Fax" SIZE="20">
Sales Rep:<input NAME="SalesRep" SIZE="5">
<input TYPE="submit" NAME="requestedAction" VALUE="First">
<input TYPE="submit" NAME="requestedAction" VALUE="Next">
<input TYPE="submit" NAME="requestedAction" VALUE="Prev">
<input TYPE="submit" NAME="requestedAction" VALUE="Last">
<input TYPE="submit" NAME="requestedAction" VALUE="Save">
<input TYPE="submit" NAME="requestedAction" VALUE="Add">
<input TYPE="submit" NAME="requestedAction" VALUE="Delete">
<input TYPE="submit" NAME="requestedAction" VALUE="Reset">
<input TYPE="submit" NAME="requestedAction" VALUE="Cancel">
</pre>
</form>
</body>
</html> 

You can use the HTML Mapping Wizard’s Automap feature to map the fields referenced in w-custdir.htm to the database fields referenced in dcustomer.w. Note that all the fields will map except the hidden fields and the SearchName field (shown in bold). These fields are used to pass information to the WebSpeed Agent and do not reference fields in the database.

The hidden field, cusrowid, holds a value that identifies the current record that is displayed on the Web page. It establishes a context for the WebSpeed Agent when the next request is submitted. The other hidden field, AddMode, holds a value that tells the WebSpeed Agent if a new record is to be added or not when the next request is submitted. The code that utilizes these hidden fields is explained in the following section.

Adding Code

After the HTML Mapping Wizard completes, you will see a tree view of an untitled Web object, which is similar to Figure 4–8.

Figure 4–8: Tree View of an Untitled HTML-mapping Object

From the Code Sections branch of the tree view, you can add all the code that is necessary to complete w-custdir.w. With Code Sections selected, choose the Edit Code button from the AppBuilder Tool Bar to start the Section Editor. The Section Editor allows you to add new procedures, to modify default procedures, and to invoke and override super procedures. For more information, see the Progress AppBuilder Developer’s Guide.

You will need to do the following in order to complete the Web object:

  1. Create a trigger that responds to the value of cusrowid.
  2. In the trigger, the value of cusrowid is passed to the setCurrentRowids procedure. Recall that the value of cusrowid is stored in a hidden field and is set in a prior WebSpeed transaction. The trigger essentially tells the WebSpeed Agent which row in the table to refer to. In other words, the trigger establishes a context for the WebSpeed Agent by passing information about a previous transaction.

    In the example Web object, the trigger is called Web.input and the code looks similar to the following:

    Web.input 
    /*---------------------------------------------------------------------
      Purpose:     Assigns form field data value to frame screen value.
      Parameters:  p-field-value
      Notes:       This input trigger of the hidden field cusrowid sets the
                   current row to the one in the hidden field to set the
                   context in preparation for further processing.
    ---------------------------------------------------------------------*/
      DEFINE INPUT PARAMETER p-field-value AS CHARACTER NO-UNDO.
      
      DO WITH FRAME {&FRAME-NAME}:
        setCurrentRowids (p-field-value).
      END.
      
    END PROCEDURE. 
    

  3. Create a procedure that responds to the AddMode flag.
  4. In the example Web object the procedure is called inputFields and the code looks similar to the following:

    inputFields 
    /*---------------------------------------------------------------------
      Purpose:     Super Override
      Parameters:  
      Notes:  After standard behavior for this procedure, this procedure
      override looks at a hidden field called AddMode, and sets a flag
      indicating that this record is new, and must be created in the
      database before the fields are assigned.  The AddMode flag is then
      turned off in preparation for sending the next page.
    ---------------------------------------------------------------------*/
     RUN SUPER.
     
     IF  ab_unmap.AddMode:screen-value in frame {&FRAME-NAME} = "YES" THEN
     DO:
      PleaseAdd = TRUE.
      setAddMode (TRUE).
     END.
     IF  ab_unmap.AddMode:screen-value in frame {&FRAME-NAME} = "NO" THEN
     DO:
       PleaseAdd = FALSE.
       setAddMode (FALSE).
     END.
     ab_unmap.AddMode:screen-value in frame {&FRAME-NAME} = "No".
    
    END PROCEDURE. 
    

    As noted in the comment, this procedure is actually an override to the inputFields super procedure. This override supplements the standard behavior of inputFields by allowing it to react to the value of the AddMode flag in the hidden field. This code allows the Web object to add a new record to the database.

  5. Create a procedure that manages the unmapped fields.
  6. In the example Web object, the procedure is called outputFields and the code looks similar to the following:

    outputFields 
    /*---------------------------------------------------------------------
      Purpose:     Super Override
      Parameters:  
      Notes: This outputs the current record to the hidden field cusrowid
      before standard behavior for this procedure and outputs the AddMode
      hidden field.
    ---------------------------------------------------------------------*/
    IF getUpdateMode() = "Add" THEN
        ab_unmap.AddMode:screen-value in frame {&FRAME-NAME} = "YES".
    ELSE
        ab_unmap.AddMode:screen-value in frame {&FRAME-NAME} = "NO".
    
    ab_unmap.cusrowid:screen-value in frame {&FRAME-NAME} = getRowids().
        
    RUN SUPER.
    
    END PROCEDURE. 
    

    As noted in the comment, this procedure is actually an override to the outputFields super procedure. Its purpose is to identify the correct row for the next transaction. This override sets the value of ab_unmap.custrowid to the rowid of the current record. The value of ab_unmap.custrowid is set before running outputFields.

    The ab_unmap temporary table holds the values of the fields that are unmapped. In this example, the unmapped fields are cusrowid, SearchName, and AddMode.

    NOTE: The AppBuilder online help contains reference pages that describe the syntax and behavior inputFields, outputFields, and all other super procedures that apply to WebSpeed. For more information about using super procedures, see the Progress ADM 2 Guide and the Progress ADM 2 Reference.

  7. Modify process-web-request so that the Web object responds to button events.
  8. The button events are handled in a case statement, as shown in the following segment:

    process-web-request 
      IF REQUEST_METHOD = "POST":U THEN DO:  
        RUN inputFields. 
        RUN findRecords.
        CASE get-field ("requestedAction"):
            WHEN "First" THEN 
              RUN fetchFirst.           
            WHEN "Next" THEN
              RUN fetchNext.          
            WHEN "Prev" THEN 
              RUN fetchPrev.         
            WHEN "Last" THEN 
              RUN fetchLast.           
            WHEN "Search for Name" THEN DO:
              addSearchCriteria(’name’,get-value(’searchname’)).   
              RUN findRecords.    
            END.
            /* Maintenance action selected  */
            WHEN "Save" THEN DO:
                IF getUpdateMode () <> "add" THEN
              RUN fetchCurrent. 
              RUN assignFields.
              setAddMode (FALSE).
              setUpdateMode ("").
            END.
            WHEN "Delete" THEN DO:
              RUN fetchCurrent. 
              deleteRow(). 
            END.
            WHEN "Reset" THEN DO:
              RUN fetchCurrent.  
            END.
            WHEN "Cancel" THEN DO: 
              RUN fetchCurrent.
              setUpdateMode ("").
            END.
            WHEN "Add" THEN DO: 
              RUN fetchCurrent.
              setUpdateMode ("Add").
            END.
        END CASE. 
    


Copyright © 2004 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095