Try OpenEdge Now
skip to main content
ABL Essentials
Defining and Using Temp-tables : Adding an Order Line browse to the Customer window
 

Adding an Order Line browse to the Customer window

You've completed the h-fetchOlines.p procedure. When it ends, it returns a temp-table with the OrderLines for the Order in it, along with the name and weight total from the Item table.
To use an include file to put the same code in multiple procedures:
1. Open h-fetchOlines.p and copy the temp-table definition.
2. Paste it into a new procedure window and save the procedure as h-ttOline.i:
/* h-ttOline.i -- include file to define ttOline temp-table. */
DEFINE TEMP-TABLE ttOline LIKE Orderline
  FIELD ItemName    LIKE ITEM.ItemName
  FIELD TotalWeight AS DECIMAL LABEL "Tot.Wgt.".
3. Remove the code from h-fetchOlines.p (or just comment it out to remind you of what the include file replaces), and put in a reference to h-ttOline.i in its place:
/* h-fetchOlines.p -- retrieve all orderlines for an Order
   and return them in a temp-table. */
   {h-ttOline.i}
/* DEFINE TEMP-TABLE ttOline LIKE OrderLine
   FIELD ItemName LIKE ITEM.ItemName
   FIELD TotalWeight AS DECIMAL LABEL "Tot.Wgt." . */

DEFINE INPUT PARAMETER piOrderNum AS INTEGER NO-UNDO.
DEFINE OUTPUT PARAMETER TABLE FOR ttOline.

FOR EACH OrderLine WHERE Orderline.OrderNum = piOrderNum,
  Item OF OrderLine:
  CREATE ttOline.
  BUFFER-COPY OrderLine TO ttOline
    ASSIGN ttOline.ItemName = ITEM.ItemName
           ttOline.TotalWeight = OrderLine.Qty * ITEM.Weight.
END.
Remember that part of the purpose of this exercise is to give you a taste of what it is like to write separate ABL procedures for user interfaces and for data access and update code, so that you can ultimately distribute those procedures between client and server machines in a true enterprise application. In this simple example, both procedures run as part of the same session, but they could run more or less exactly the same in different OpenEdge sessions on completely different machines.
To add code to the CustOrderWin procedure to run h-fetchOlines.p and display the OrderLines in a browse of their own:
1. Open h-CustOrderWin4.w in the Procedure Editor.
2. In the Definitions section, add a reference to h-ttOline.i:
{h-ttOline.i}
/* DEFINE TEMP-TABLE ttOline LIKE Orderline
   FIELD ItemName LIKE ITEM.ItemName
   FIELD TotalWeight AS DECIMAL LABEL "Tot.Wgt.". */
3. Add a query definition for a query on this temp-table:
DEFINE QUERY OlineQuery FOR ttOline.
4. Put this browse definition for the temp-table after the other elements in the Definitions section. Select these fields from the ttOline table, including the Item Name and Weight from the Item table:
DEFINE BROWSE OlineBrowse
  QUERY OlineQuery NO-LOCK
    DISPLAY
      ttOline.Ordernum
      ttOline.LineNum LABEL "Line"
      ttOline.ItemNum LABEL "Item" FORMAT "ZZZ9"
      ttOline.ItemName FORMAT "x(20)"
      ttOline.TotalWeight
      ttOline.Price FORMAT "ZZ,ZZ9.99"
      ttOline.Qty
      ttOline.Discount
      ttOline.ExtendedPrice LABEL "Ext.Price" FORMAT "ZZZ,ZZ9.99"
    WITH NO-ROW-MARKERS SEPARATORS 7 DOWN ROW-HEIGHT-CHARS .57.
Remember that your BUFFER-COPY from the OrderLine table gives you all the fields from that table in your temp-table, but you don't have to use all of them in the browse.
You define the number of rows to display with the 7 DOWN phrase and leave out the size altogether. That way, the AVM displays all seven rows of data and is wide enough to display all the fields you have selected.
Now, you need to run the procedure that fetches the Order Lines each time a row is selected in the Order browse. The event that is fired when a row is selected is called VALUE-CHANGED.
5. In the Control Triggers section define this trigger on VALUE-CHANGED of the OrderBrowse:
ON VALUE-CHANGED OF OrderBrowse IN FRAME CustQuery DO:
  RUN h-fetchOlines.p (INPUT Order.OrderNum, OUTPUT TABLE ttOline).
  OPEN QUERY OlineQuery FOR EACH ttOline.
  DISPLAY OlineBrowse WITH FRAME CustQuery.
  ENABLE OlineBrowse WITH FRAME CustQuery.
END.
The trigger code runs the procedure, passing in the current Order number from the Order buffer and getting a temp-table back. Then it opens the OlineQuery. Because the DEFINE BROWSE statement associates the query with the new browse, the rows from the temp-table are automatically displayed in the browse. The DISPLAY statement displays the browse itself in the same frame with everything else. Without more specific instructions on where to place it, the AVM places it to the right of the last object that is already defined for the frame, which is the Order browse. You could also use ROW and COLUMN attributes on the DISPLAY statement to display the new browse somewhere else. Finally, enabling the browse lets the user select rows in it and scroll in it if it has too many rows to display at once. This code does not enable the individual cells in the browse for update.
The VALUE-CHANGED trigger fires whenever the user selects a different row in the browse. But there are two other times when a row is selected. The first is when the window first comes up. The Order browse then holds the Orders for the first Customer, and the first of those Orders is selected implicitly.
Make sure the VALUE-CHANGED trigger fires at that time, in the Main Block of the window procedure, by adding a line to APPLY the VALUE-CHANGED trigger on startup:
MAIN-BLOCK:
DO ON ERROR UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
  ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
  RUN enable_UI.
  ASSIGN cState   = Customer.State
         iMatches = NUM-RESULTS("CustQuery").
  DISPLAY cState iMatches WITH FRAME CustQuery.
  APPLY "VALUE-CHANGED" TO OrderBrowse.
END.
The second place where an Order is implicitly selected is whenever the user presses one of the buttons that selects a new Customer. This reopens the Order query, and you want the OrderLines for the first Order for that Customer to be retrieved.
Because there are four buttons with almost exactly the same code on them, this is another good place to use an include file. As mentioned earlier, the one keyword that is different in these triggers is whether it is a GET FIRST, NEXT, PREV, or LAST. So you make that keyword an argument to the include file.
6. Create an include file for the four buttons:
a. Copy the code from the BtnFirst CHOOSE trigger and paste it into a new procedure window.
b. Replace the FIRST keyword with the include file argument marker {1}.
c. Add the same statement as you did in the Main Block to APPLY the VALUE-CHANGED event.
d. Save this code as h-ButtonTrig1.i, as shown:
/* h-ButtonTrig1.i -- include file for the First/Next/Prev/Last
   buttons in h-CustOrderWin4.w. */
  GET {1} CustQuery.
  IF AVAILABLE Customer THEN
  DISPLAY Customer.CustNum Customer.Name Customer.Address
    Customer.City Customer.State
    WITH FRAME CustQuery IN WINDOW CustWin.
  {&OPEN-BROWSERS-IN-QUERY-CustQuery}
  APPLY "VALUE-CHANGED" TO OrderBrowse.
7. In each of the four CHOOSE triggers, replace the trigger code with a reference to the h-ButtonTrig.i include file, passing in the appropriate GET keyword, as in this BtnFirst trigger:
{ h-ButtonTrig1.i FIRST }
Now your procedure is ready to retrieve and display OrderLines.
8. Widen the window and its frame substantially by dragging the right edge out further to the right, to make room for the OrderLine browse.
9. Run the window to see the effect of your changes: