Now you can try out some of the things you learned about queries.

To extend the sample application window to use some query statements:

  1. In AppBuilder, open h-CustOrderWin1.w.

    This gives you the test procedure with Customer fields and the Order browse but without some of the other graphical objects you added later.

  2. Extend the window somewhat to the right, then drop two buttons onto the window to the right of the Last button.
  3. Name the first button PosButton and give it a label of Save Position.
  4. Name the second button ReposButton and give it a label of Restore Position.
  5. Open the Section Editor and select the Definitions section.
  6. Define a variable to hold a value for the Customer query’s CURRENT-RESULT-ROW:
    /* Local Variable Definitions ---                                  */
    DEFINE VARIABLE iQueryRow AS INTEGER NO-UNDO.

    Remember that the Definitions section is scoped to the entire procedure file, so anything you define here is available to any trigger or internal procedure inside it.

  7. Go into the Triggers section for the PosButton and give it this CHOOSE trigger:
    DO:
      iQueryRow = CURRENT-RESULT-ROW('CustQuery').
    END.
  8. Define this CHOOSE trigger for the ReposButton:
    DO:
      REPOSITION CustQuery TO ROW iQueryRow.
      APPLY "CHOOSE" TO BtnNext.
    END.

    When you click the Save Position button, your code saves off the current row number from the results list. You can then move around in the query. When you press the Restore Position button, the Customer query is repositioned to the row you saved, and the Order query is opened for that Customer.

    Why did you need the APPLY "CHOOSE" TO BtnNext statement? Remember that when you use the REPOSITION statement the AVM positions before the record you want, so you need to execute a GET NEXT to make it available. At the same time, in this case, your code needs to reopen the dependent Order query for the Customer as well. All this is done by the trigger code on the Next button.

  9. Run the procedure and test saving off and restoring the current row.
  10. Add a fill-in field to give you a reason to test reopening the query with a different WHERE clause:
    1. Drop a fill-in on the window. Call it cState and give it a label of New State.
    2. Write this LEAVE trigger for the fill-in field in the Section Editor:
      DO:
        OPEN QUERY CustQuery FOR EACH Customer WHERE State =
          cState:SCREEN-VALUE BY Customer.City.
        APPLY "CHOOSE" TO BtnFirst.
      END.

    Each time you enter a state abbreviation in the field and tab out of it, the trigger fires and the query is reopened with that new state. Remember that it is not necessary to close a query explicitly if you are immediately going to reopen it, so a CLOSE QUERY CustQuery statement here is optional. Also remember that unless you specifically assign it using the ASSIGN statement, the value the user types into the fill-in exists only in the frame’s screen buffer, so you can retrieve it using the SCREEN-VALUE attribute of the field.

    Similarly for the CHOOSE trigger that repositions to the previously saved row, you need to apply CHOOSE to the First button trigger to get the first row for the new query and reopen the Order query.

  11. Run your procedure. You can enter a state name and tab out of the New State field and see the Customers in that state along with their Orders:

    If you enter an invalid state name, the procedure does not give you any feedback to confirm this. In the next section, you make a few more changes to the procedure to check whether there were any results for the state that is entered. This makes use of the NUM-RESULTS function and also introduces you to another new and useful ABL statement.