Filling a COMBOBOX item list

The item list of COMBOBOX fields can be initialized at runtime.

Introduction to COMBOBOX fields

COMBOBOX fields are typically used when a field can hold a short predefined list of values. COMBOBOX fields are usually rendered with a drop-down list, from where the end user can choose a value.

All items of a COMBOBOX list will be transmitted to the front-end. Therefore, the number of items that can be selected in a COMBOBOX fields should be limited to 20 to 50 items. If the selection list holds more items, consider using a BUTTONEDIT field, which opens a new window with a TABLE container.

COMBOBOX item lists can be defined in three different ways:
  1. In the form definition file, as a static list of items with single values.
  2. In the form definition file, as a static list of items with value/label pairs.
  3. At runtime when the form is loaded, as single values or value/label pairs.

In this topic we will learn how to implement a COMBOBOX field that is filled dynamically.

For static item list definitions, see COMBOBOX item type.

Defining the COMBOBOX initialization function

In order to fill a COMBOBOX field when the form file is loaded, use the INITIALIZER attribute to define the name of the function that will be called to fill the item list:

COMBOBOX f1 = FORMONLY.city, INITIALIZER = init.fill_city;

The INITIALIZER attribute accepts a module prefix for the initializer function. When a module is specified, it will be loaded on demand to resolve the function symbol at runtime when the form is displayed. When specifying only a function name, make sure that the initialization function is available when the form is displayed: Use for example IMPORT FGL of the module, and call one of the functions of that module before displaying the form.

The initialization function name is case insensitive.

The module prefix of the initialization function name is case sensitive (unlike the function name, which is case insensitive). If the module is not yet loaded, it will be loaded automatically when the initializer function is needed.

Defining a global COMBOBOX initialization function

If needed, it is possible to define a common function that implements the item list initialization for all comboboxes of the forms loaded by a program, by using the ui.Combobox.setDefaultInitializerFunction() method.
Tip:

Use the TAG attribute to distinguish COMBOBOX fields in all your forms.

Implementing the item list initialization function

The function defined with the INITIALIZER attribute takes a ui.ComboBox object as parameter.

To add items to the selection list of the COMBOBOX field, use the addItem() method of ui.ComboBox:

FUNCTION fill_city( comboBox ui.ComboBox ) RETURNS ()
    CALL comboBox.addItem(101,"Berlin")
    CALL comboBox.addItem(102,"Madrid")
    CALL comboBox.addItem(103,"London")
    CALL comboBox.addItem(104,"Paris")
    CALL comboBox.addItem(105,"Rome")
END FUNCTION

If you want to define a list of items with single values, specify only the first parameter of addItem().

Detecting COMBOBOX value change

In order to detect a value change in a COMBOBOX, define the ON CHANGE dialog control block. The ON CHANGE block will be immediately executed when the user selects a new item in the list. One can typically clear other fields related to the COMBOBOX field:

   ON CHANGE city
      LET rec.address = NULL

NULL values in COMBOBOX fields

Pay attention to NULL value handling with COMBOBOX fields:
  • By default, if the field allows nulls, the item list automatically gets a NULL item.
  • It is recommend to disallow nulls with the NOT NULL attribute, and add a special item such as (0,"<Undefined>") to identify a non-specified-value.

Example

The next example shows how to implement the function to fill the item list of a COMBOBOX field with a list of cities. When the COMBOBOX field is changed, the ON CHANGE block is fired and the address field is cleared:

Form file (combobox.per):
LAYOUT
GRID
{
City   : [f1                      ]
Address: [f2                                              ]
}
END
END
ATTRIBUTES
COMBOBOX f1 = FORMONLY.city, INITIALIZER=combobox.fill_city;
EDIT f2 = FORMONLY.address;
END
Program file (combobox.4gl):
MAIN
    DEFINE rec RECORD
               city INTEGER,
               address VARCHAR(100)
           END RECORD

    OPEN FORM f1 FROM "combobox"
    DISPLAY FORM f1

    INPUT BY NAME rec.* ATTRIBUTES(UNBUFFERED)
        ON CHANGE city
           LET rec.address = NULL
    END INPUT

END MAIN

FUNCTION fill_city(cmb ui.ComboBox) RETURNS ()
    CALL cmb.addItem(101,"Berlin")
    CALL cmb.addItem(102,"Madrid")
    CALL cmb.addItem(103,"London")
    CALL cmb.addItem(104,"Paris")
    CALL cmb.addItem(105,"Rome")
END FUNCTION