Add an Order Line browse to the Customer window
- Last Updated: April 10, 2024
- 4 minute read
- OpenEdge
- Version 13.0
- Documentation
You 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:
- Open h-fetchOlines.p in AppBuilder and copy the temp-table definition.
- 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.". - 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 NO-LOCK WHERE Orderline.OrderNum = piOrderNum, Item OF OrderLine NO-LOCK: 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:
- Open h-CustOrderWin4.w in AppBuilder.
- In the Definitions section, add a reference to
h-ttOline.i:{h-ttOline.i} - Add a query definition for a query on this temp-table:
DEFINE QUERY OlineQuery FOR ttOline. - Put this browse definition for the temp-table after the other elements in
the Definitions section. Fields are selected 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-COPYfrom the OrderLine table gives you all the fields from that table in your temp-table, but you do not have to use all of them in the browse.You define the number of rows to display with the
7 DOWNphrase 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.Note: Because you did not create the Browse definition using the AppBuilder Palette, it will not be visible in the Design window. However, it will be visible when you run the application. - 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.In the Section Editor, define this trigger on the
VALUE-CHANGEDof the OrderBrowse: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 BROWSEstatement associates the query with the new browse, the rows from the temp-table are automatically displayed in the browse. TheDISPLAYstatement 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 useROWandCOLUMNattributes on theDISPLAYstatement 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-CHANGEDtrigger 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-CHANGEDtrigger fires at that time, in the Main Block of the window procedure, by adding a line toAPPLYtheVALUE-CHANGEDtrigger 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, orLAST. So you make that keyword an argument to the include file. - Create an include file for the four buttons:
- Copy the
code from the
BtnFirst CHOOSEtrigger and paste it into a new procedure window. - Replace the
FIRSTkeyword with the include file argument marker{1}. - Add the same statement as you did in the Main Block to
APPLYtheVALUE-CHANGEDevent. - 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.Name Customer.CustNum Customer.Address Customer.City Customer.State WITH FRAME CustQuery IN WINDOW CustWin. {&OPEN-BROWSERS-IN-QUERY-CustQuery} APPLY "VALUE-CHANGED" TO OrderBrowse. - Copy the
code from the
- In each of the four
CHOOSEtriggers, replace the trigger code with a reference to the h-ButtonTrig.i include file, passing in the appropriateGETkeyword, as in this BtnFirst trigger:DO: { h-ButtonTrig1.i FIRST } END.Now your procedure is ready to retrieve and display OrderLines.
- Widen the window and its frame substantially by dragging the right edge out further to the right, to make room for the OrderLine browse.
- Run the window to see the effect of your changes:
Summary
In this section you have learned:
- How to define temp-tables that create result sets that do not correspond to a single database table, how to pass them as parameters, and how to display their data
- How these temp-table parameters can help you separate out the data access and business logic of your application from the user interface procedures, in preparation for building distributed enterprise applications with ABL