Feeding DISPLAY ARRAY with rows

Full list mode of DISPLAY ARRAY

In full list mode, DISPLAY ARRAY uses a complete copy of the result set to be displayed in the form array. The full list mode is typically used for a short list of rows.

In full list mode, the DISPLAY ARRAY instruction uses a static or dynamic program array defined with a record structure corresponding to (or to a part of ) a screen-array in the current form. The program array is filled with data rows before DISPLAY ARRAY is executed. In this case, the list is static and cannot be updated until the instruction is exited.


Full list mode diagram

Figure 1. Full list mode in DISPLAY ARRAY diagram

Paged mode of DISPLAY ARRAY

When implementing a read-only list with a DISPLAY ARRAY, it is possible to use the paged mode with the ON FILL BUFFER block. The paged mode allows the program to display a very large number of rows, without copying all database rows into the program array. The program array holds only the current visible page.


Paged mode diagram

Figure 2. Paged mode diagram

DISPLAY ARRAY has some limitation in the paged mode: The user cannot sort data by clicking on a column header; multi-range selection is not supported if the paged mode uses an undefined number of rows (COUNT=-1); To fill a tree view dynamically, use the ON EXPAND / ON COLLAPSE data blocks.

In paged mode, the dynamic array holds a page of rows, not all rows of the result set. Therefore, you must specify the total number of rows with the COUNT attribute in the ATTRIBUTES clause of DISPLAY ARRAY. The number of rows can be changed during dialog execution with the ui.Dialog.setArrayLength() method. In singular DISPLAY ARRAY instructions, you define the total number of rows of a paged mode with the SET_COUNT() built-in function or the COUNT attribute. But these are only taken into account when the dialog starts. If the total number of rows changes during the execution of the dialog, the only way to specify the number of rows is DIALOG.setArrayLength().

The ON FILL BUFFER clause is used to fill a page of rows in the dynamic array, according to an offset and a number of rows. The offset can be retrieved with the FGL_DIALOG_GETBUFFERSTART() built-in function, and the number of rows to provide is defined by the FGL_DIALOG_GETBUFFERLENGTH() built-in function. The ON FILL BUFFER is triggered when all the user code is executed and the dialog gets the control back, this means that the fill clause is not immediately fired when calling DIALOG.setArrayLength().

If the total number of rows is unknown when at dialog start, define the COUNT attribute to -1. The dialog will then ask for rows with ON FILL BUFFER, until you provide less rows as expected for the page, or if you reset the total number of rows to a value higher value as -1 with the ui.Dialog.setArrayLength() method. Note that the dialog cannot support multi-row selection when the total number of rows is undefined.

It is not possible to use treeview decoration when the dialog uses the paged mode: For treeviews, the dialog needs the complete set of open nodes with parent/child relations to handle the tree view display. With the paged mode only a short window of the dataset is known by the dialog. If you use a tree view with a paged mode DISPLAY ARRAY, the program will raise an error at runtime.

A typical paged DISPLAY ARRAY implementation consists of a scroll cursor providing the list of records to be displayed. Scroll cursors use a static result set. If you want to display fresh data, you can implement an advanced paged mode by using a scroll cursor that provides the primary keys of the referenced result set, plus a prepared cursor to fetch rows on demand in the ON FILL BUFFER clause. In this case you may need to check whether a row still exists when fetching a record with the second cursor.

The following example shows a DISPLAY ARRAY implementation using a scroll cursor to fill pages of records in ON FILL BUFFER, specifying an undefined number of rows (COUNT=-1).
MAIN
  DEFINE arr DYNAMIC ARRAY OF RECORD
            id INTEGER,
            fname CHAR(30),
            lname CHAR(30)
        END RECORD 
  DEFINE cnt, ofs, len, row, i INTEGER
  DATABASE stores7
  OPEN FORM f1 FROM "custlist"
  DISPLAY FORM f1
  DECLARE c1 SCROLL CURSOR FOR
         SELECT customer_num, fname, lname FROM customer 
  OPEN c1
  DIALOG ATTRIBUTES(UNBUFFERED)
    DISPLAY ARRAY arr TO sa.* ATTRIBUTES(COUNT=-1)
      ON FILL BUFFER
        CALL arr.clear()
        LET ofs = fgl_dialog_getBufferStart()
        LET len = fgl_dialog_getBufferLength()
        LET row = ofs 
        FOR i=1 TO len 
          FETCH ABSOLUTE row c1 INTO arr[i].*
          IF SQLCA.SQLCODE!=0 THEN
            CALL DIALOG.setArrayLength("sa",row-1)
            EXIT FOR
          END IF
          LET row = row + 1
        END FOR
    END DISPLAY
    ON ACTION ten_first_rows_only 
      CALL DIALOG.setArrayLength("sa", 10)
    ON ACTION quit 
       EXIT DIALOG
  END DIALOG
END MAIN