Getting started with CGIDEV2 -- Part 3

Previously Paul Tuohy showedyou how to write a report using CGIDEV2 to produce a simple report for the Web, as well as introduced you to the basic format of an HTML form. Now it's time to look at how you can write a simple subfile program and a maintenance program.

This Content Component encountered an error

My previous articles on CGIDEV2 ("Getting Started with CGIDEV2 – Part 1" and "Getting started with CGIDEV2 -- Part II"), I discussed how to write a program using CGIDEV2 to produce a simple report for the Web and how to write a "paging" report. I also introduced the basic format of an HTML form. In this article, it is time to look at how you can write a simple subfile program and a maintenance program.

Figure 1 shows an example of a "Load All" style subfile Web page. The user can add a new product by keying in the new product code and clicking the Add button. Alternatively, he can update or delete an existing product by simply clicking on the product code.

Figure 1: A "Load All" style subfile Web page

Figure 2 shows the Web page displayed when the user opts to add a new product. The user enters the values and clicks the Add button to add the product.

Figure 2: Adding a new product

Figure 3 shows the Web page displayed when the user selects an existing product. The user makes the required changes and clicks either the Change or Delete button.

For both add and change, the category code is selected from a drop down box; whereas the user selects a category description it is actually the category code that is returned to the program. This is the HTML equivalent of an F4 prompt where the list of available options is of a manageable size.

Also note how the picture of the product is displayed.

Figure 3: Maintaining an existing product

The subfile page
Figure 4 shows the HTML for the subfile page. In the tablestart section the definition of the form addCode allows for the entry of a new product code by issuing a call to CVALL002B when the Add button is selected. Each product code listed in the table (tableline section) has a hyperlink to call CVALL002B with the product code as a parameter.

<!-- $top$ -->
Content-type: text/html

<html>
<!-- Standard Work With Selection Table -->
  <head>
       <title>Work With Products</title>
       <link rel="stylesheet" type = "text/css" href="/cgiseminar/StyleSheet.css">
  </head>

  <body>
      <center>
       <h1>RPG Meets the Web!</h1>
       <h2>Work With Products</h2>
      </center>


<!-- $tablestart$ -->
      <table border=1 CellSpacing=2 CellPadding=2 Width="500">
        <tr align=Left><td>Product<br>Code</td>
                       <td>Description</td>
        </tr>

        <tr align=left>
        <form name="addCode" action="/cgi-bin/cvall002b" method="POST">
              <td><input type="text" name="cgiprodcd" size=8 maxlength=7
                   value=" "></td>
              <td><input type="submit" value="Add"></td>
        </form>
        </tr>

<!-- $tableline$ -->
        <tr align=left>
              <td><<a href = "/cgi-bin/cvall002b?cgiprodcd=<!-- %prodcd% -->">
                              <!-- %prodcd% --></a></td>
              <td><!-- %prodds% --></td>
        </tr>

<!-- $end$ -->

      </table><hr>
      <a href="/cgiseminar/CGIExamples.html">Return to Index</a>

  </body>
</html>

Figure 4: HTML for "Load All" style subfile

Are you ready for the complicated subfile program? Figure 5 shows the source of the CGIDEV2 program CVALL002A. Your eyes do not deceive you; that is all there is. The program bears a striking resemblance to the original report program in that it simply lists all of the products. The enormous benefit of using HTML is that the program does not need to process the subfile because any actions are initiated directly from the HTML (i.e. all calls to CVALL002B are initiated from the HTML).

H Option(*SrcStmt: *NoDebugIO) DftActGrp(*No) BndDir('RPGBROWSE')
 //----------------------------------------------------------
 //
 //          CGI Application
 //
 //          Paul Tuohy, ComCon
 //
 //----------------------------------------------------------
 //
 // CVALL002A:- Work with Products Using CGIDEV2
 //
 //----------------------------------------------------------
FProduct1  IF A E           K DIsk    ExtFile('CGISEMINAR/PRODUCT1')

 /copy prototypeb
 /copy usec

 //===================================================================
 // Main line
 //===================================================================

 /FREE
    gethtmlIFS('/cgiseminar/cvall002a.html':'<!-- $':'$ -->':
                                            '<!-- %':'% -->');

    wrtsection('top');

    wrtsection('tablestart');

    SetLL *Loval Product1;
    Read Product1;
    Dow Not %EOF(Product1);

        updHTMLvar('prodcd':prodcd);
        updHTMLvar('prodds':prodds);
        wrtsection('tableline');

        Read Product1;
    EndDo;

    wrtsection('end *fini');
    return;
 /END-FREE

Figure 5: The subfile program

The maintenance program
Before we look at the maintenance program, I just want to point out that this is just one of many ways of providing a maintenance function. In this example there is one program that provides for the loading, displaying and validation of the Web page and as well as adds, updates or deletes the record. Another option is to divide this into separate programs for the load/display and the validation/process.

Figure 6 shows the HTML for the maintenance program. The Web page is basically a form that calls the program CVALL002B. The main sections are changebutton and addbutton (towards the end of the page); one of those will be written depending on whether a product is being added or changed. All of the submit buttons have the same name of CGIOption, which is used by the maintenance program to determine if a product is to be added, updated or deleted. Also make a note of the selectoption section, which is used to generate the drop down list for category selection; the lines preceding and following selectoption identify the HTML select name. And then there are the MsgStart, MsgL1 and MsgEnd sections, which are used to display error messages.

<!-- $top$ -->
Content-type: text/html

<html>
<!-- Standard Work With Maintenance -->
  <head>
       <title>Work With Products</title>
       <link rel="stylesheet" type = "text/css" href="/cgiseminar/StyleSheet.css">
  </head>
  <body>
      <center>
<h1>RPG Meets the Web!</h1>
       <h2>Work With Products</h2>
      </center>

<!-- $tablestart$ -->        
      <form name="setProduct" action="/cgi-bin/cvall002b" method="POST">
      <table border=0 CellSpacing=2 CellPadding=2 Width="500" align=left>

        <tr><td>Product Code</td>
            <td><!-- %prodcd% --><input type="hidden" name="cgiprodcd" 
                 value="<!-- %prodcd% -->" </td></tr>
        <tr><td>Description</td>
            <td><input type="text" name="cgiprodds" size=40 maxlength=30
                 value="<!-- %prodds% -->"></tr>
        <tr><td>Category Code</td>
            <td><select name="cgicatcod">
<!-- $selectoption$ -->     
            <!-- %selectcategory% --> 
<!-- $tableend$ -->         
            </select></td></tr>
        <tr><td>Stock On Hand</td>
            <td><input type="text" name="cgistoh" size=15 maxlength=7 
                 Value="<!-- %stoh% -->"></tr>
        <tr><td>Landed Cost</td>
            <td><input type="text" name="cgilndcst" size=15 maxlength=11 
                 value="<!-- %lndcst% -->"></tr>
        <tr><td>Selling Price</td>
            <td><input type="text" name="cgisellpr" size=15 maxlength=11 
                 value="<!-- %sellpr% -->"></tr>
        <tr><td>Last Delivery Date</td>
            <td><input type="text" name="cgidatea" size=15 maxlength=8 
                 value="<!-- %dtlord% -->"></tr>
     </table>

<!-- $changebutton$ -->     
            <input type="submit" name="cgioption" value="Change">
            <input type="submit" name="cgioption" value="Delete">
            <br><a href="/cgiseminar/CGIExamples.html">Return to Index</a>
            <br><img border=0 src="/cgiseminar/Images/P<!-- %prodcd% -->F.JPG">

<!-- $addbutton$ -->        
            <input type="submit" name="cgioption" value="Add">


<!-- $endform$ -->           
        </form>


<!-- $MsgStart$ -->
Errors:

<!-- $MsgL1$ -->
<p><font color=#FF0000>/%msgtext%/</font></p>

<!-- $MsgEnd$ -->
<hr>

<!-- $continue$ -->          
   <b>Product <!-- %prodcd% --> <!-- %prodds% --> has been 
              <!-- %option% -->ed.<br></b>
   <a href = "/cgi-bin/cvall002a"> Click here</a> to select another.<br><br>
   <a href="/cgiseminar/CGIExamples.html">Return to Index</a>


<!-- $end$ -->               

  </body>
</html>

Figure 6: HTML for the maintenance program

Figure 7 shows the CGIDEV2 maintenance program CVALL002B. The main points of the mainline are as follows:

  1. The program uses an indicator (LoadPage) to determine whether a page should be loaded and displayed.
  2. The HTML is loaded using gethtmlIFS.
  3. A call is made to the CGIDEV2 subprocedure ClrMsgs to clear any existing error messages.
  4. CGIOption and CGIProdCd are set from the input. The program was called from the CVALL002B Web page if CGIOption is not blank, so the data needs to be validated; otherwise the program was called from the CVALL002A Web page, so the record needs to be retrieved.
  5. The Web page is displayed or the record is processed, depending on the value of the LoadPage indicator. The indicator will be true if the program was called from the CVALL002A Web page or if any of the data entered was invalid.

H Option(*SrcStmt: *NoDebugIO) DftActGrp(*No) BndDir('RPGBROWSE')
 //----------------------------------------------------------
 //
 //          CGI Application
 //
 //          Paul Tuohy, ComCon
 //
 //----------------------------------------------------------
 //
 // CVALL002B:- Work with Products (Maintenance) Using CGIDEV2
 //
 //----------------------------------------------------------
FCategor1  IF   E           K DIsk    ExtFile('CGISEMINAR/CATEGOR1')
FProduct1  UF A E           K Disk    ExtFile('CGISEMINAR/PRODUCT1')

 /copy prototypeb
 /copy usec

D LoadPage        S               N
D AddMode         S               N
D SavedQryStr     S          32767    Varying
D CGIOption       S              6
D CGIDatea        S              8

D CGIFile       E DS                  ExtName(Product1)
D                                     Prefix(CGI) Inz

D DataFile      E DS                  ExtName(Product1)

D DScategorIn     Ds                  LikeRec(CategorR:*Input)

D ArrCategory   E Ds                  ExtName(Categor)
D                                     Qualified Dim(500)

D NoCategorys     S              5I 0
D X               S              5I 0
D Temp            S             30    Varying
    
 //=================================================================
 // Main line
 //====================================================================
 /FREE
    loadPage = *off;

    gethtmlIFS('/cgiseminar/cvall002b.html':'<!-- $':'$ -->':
                                            '<!-- %':'% -->');

    ClrMsgs();
    Clear CGIFile;

    // Check for Input
    If ZhbGetInput(SavedQryStr: QUSEC) > 0;
        CGIOption = ZhbGetVar('CGIOption');
        CGIProdCd = ZhbGetVar('CGIProdcd');
        If CGIOption <> *Blanks;
            ExSR Validate;
        Else;
            ExSR getRec;
        EndIf;
    EndIf;

    // Display the contents of the file or update & show completion
    if loadPage;
        exsr DspFile;
    else;
        exsr process;
    endIf;

    // Send the response html buffer and exit
    wrtsection('end *fini');
    return;

  //==========================================================
  // GetRec - Get the database record.
  //==========================================================
  BegSR GetRec;
      loadPage = *ON;
      addMode = *Off;

      Chain(N) CGIProdCd Product1;

      If Not %Found(Product1);
          Clear *NOKEY ProductR;
          CGIDateA = *Blanks;
          ProdCd = CGIProdCd;
          catcod = ArrCategory(1).CatCod;
          addMode = *On;
      else;
          If DtLOrd <> 0;
              CGIDateA = %Char(%Date(DtlOrd:*YMD):*DMY/);
          else;
              CGIDateA = *Blanks;
          EndIf;
      EndIf;

  EndSR;
  //==========================================================
  // validate the input from the web page
  //==========================================================
  BegSR Validate;

      CGIProdDs = ZhbGetVar('CGIProdDs');
      CGICatCod = ZhbGetVar('CGICatCod');
      Temp = ZhbGetVar('CGIstoh');
      If Temp <> *Blanks;
          CGISTOH = C2N2(Temp);
      EndIf;
      Temp = ZhbGetVar('CGILndCst');
      If Temp <> *Blanks;
          CGILndCst = C2N2(Temp);
      EndIf;
      Temp = ZhbGetVar('CGISellPr');
      If Temp <> *Blanks;
          CGISellPr = C2N2(Temp);
      EndIf;
      CGIDateA = ZhbGetVar('CGIdatea');

      If CGIOption <> 'Delete';

          If CGIProdDs = *blanks;
              x = AddMsg('Product Description may not be blank':1);
          EndIF;
          If CGICatCod = *blanks;
              x = AddMsg('Category Code may not be blank':1);
          EndIF;
          If CGILndCst > CGISellPr;
              x = AddMsg('Landed Cost may not exceed Selling Price':1);
          EndIF;
          If CGIDateA <> *Blanks;
              Test(DE) *DMY/ CGIDateA;
              If %Error;
             x = AddMsg('Invalid Date - must be in DD/MM/YY format':1);
              EndIF;
          EndIF;

      EndIF;

      loadPage = (GetMsgCnt() > 0);
      if loadPage;
          DataFile = CGIFile;
          addMode = (CGIOption = 'Add');
      endIf;

  EndSR;
  //==============================================================
  // Display the contents of the file
  //===================================================================
  begsr DspFile;

      wrtsection('top');

      updHTMLvar('prodcd':prodcd);
      updHTMLvar('prodds':prodds);
      wrtsection('tablestart');

      //  Set the category list
      For x = 1 To NoCategorys;
          updHTMLvar('SelectCategory':CrtTagOpt(ArrCategory(x).CatCod:
                                                ArrCategory(x).CatDes:
                                                CatCod));
          wrtsection('selectoption');
      EndFor;

      //  set and write the rest of the data
      updHTMLvar('stoh':%char(stoh));
      updHTMLvar('lndcst':%char(lndcst));
      updHTMLvar('sellpr':%char(sellpr));
      updHTMLvar('dtlord':CGIDateA);
      wrtsection('tableend');

      //  write the add or change/delete buttons
      if addMode;
          wrtsection('addbutton');
      else;
          wrtsection('changebutton');
      endIf;

      wrtsection('endform');

      If GetMsgCnt() > 0;
          WrtMsgs();
      EndIf;

  EndSR;
  //==================================================================
  // Process a request to Add or Change a Record
  //==================================================================
  begsr Process;

      chain CGIProdCd Product1;
      prodcd = cgiProdCd;
      prodds = cgiProdDs;
      catCod = cgiCatCod;
      stoh = cgiStOH;
      lndcst = cgiLndCst;
      sellpr = cgiSellPr;
      //  Set Dates
      If CGIDateA <> *Blanks;
          DtlOrd = %Int(%Char(%Date(CGIDateA:*DMY/):*YMD0));
      else;
          dtlord = 0;
      EndIf;
      DtlChg = %Int(%Char(%Date():*YMD0));

      Select;
          When cgiOption = 'Add';
              Write ProductR;
          When cgiOption = 'Change';
              Update ProductR;
          When cgiOption = 'Delete';
              Delete ProductR;
      EndSl;

      //  write the record added/changed/deleted message
      wrtsection('top');
      updHTMLvar('prodcd':prodcd);
      updHTMLvar('prodds':prodds);
      updHTMLvar('option':cgiOption);
      wrtsection('continue');

  endsr;
  //==================================================================
  // Initialization - issue any overrides and open files
  //==================================================================
  Begsr *InzSR;
      // Load the category file into an array
      Setll *loval categor1;
      Read categorR DSCategorIn;
      DoW Not %EOF();
          NoCategorys = NoCategorys + 1;
          ArrCategory(NoCategorys) = DSCategorIn;
          Read categorR DSCategorIn;
      EndDo;
  Endsr;
 /END-FREE

Figure 7: The maintenance program

As in previous CGIDEV2 programs, the usual criteria about binding directories, copy members and work fields apply, but the important items to note are as follows:

  1. In the *INZSR routine the Category file is loaded to the data structure array ArrCategory. This array is used to load the dropdown list of available categories.
  2. The GetRec routine retrieves the requested record and sets the conditions for add or change.
  3. The Validate routine starts by loading all of the input fields from the Web page. The CGIDEV2 subprocedure C2N2 is used to convert character data to numeric data. Fields are validated if it is not a delete request. The CGIDEV2 subprocedure AddMsg is used to add error messages. Finally, if any errors were generated (indicated by the CGIDEV2 subprocedure GetMsgCnt), conditions are set to redisplay the page.
  4. The DspFile routine loads data to the Web page and displays it. The dropdown category list is generated in a loop that writes the selectoption section, but the CGIDEV2 subprocedure CrtTagOpt is used to generate the correct HTML for the selection and ensures that the list is positioned at the correct category for an existing code (the generated HTML is shown in Figure 8). The section for add or change is written to present the relevant buttons for the form. Finally, any error messages are written using the CGIDEV2 subprocedure WrtMsgs.
  5. The Process routine copies the Web fields to the database fields and duly performs a write, update or delete operation. A confirmation is displayed on the Web page.

<option value="01">Widgets</option>
<option value="02">Spanners</option>
<option value="03">Household Tools</option>
<option value="27">Screwdrivers</option>
<option value="30" SELECTED>Hammers & Widgets</option>
<option value="35">Sandpaper</option>
<option value="36">Drills</option>
<option value="40">Other Implements</option>
<option value="50">Category to Go</option>
<option value="99">dogs breakfast</option>

Figure 8: HTML generated from the CrtTagOpt subprocedure

I think you can safely say that the logic for a maintenance program is not that complicated.

I am sure that you noticed that there is no looping logic in either program. Since there is no persistence between the program and the browser, there is no need for the program to loop: a program receives data, processes it and sends a Web page.

One step further
Now you know the basic principles of how you can use CGIDEV2 to write subfile and maintenance programs. In the next article I will start looking at some of the other strange and wonderful things you can do with CGIDEV2.

---------------------------
About the author: Paul Tuohy is CEO of ComCon, an iSeries consulting company. He is the author of Re-Engineering RPG Legacy Applications and is one of the quoted industry experts in the IBM Redbook "Who Knew You Could Do That With RPG IV?"


This was first published in September 2005

Dig deeper on Web Development

0 comments

Oldest 

Forgot Password?

No problem! Submit your e-mail address below. We'll send you an email containing your password.

Your password has been sent to:

-ADS BY GOOGLE

SearchEnterpriseLinux

SearchDataCenter

Close