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.

Note: 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.

Important: The initialization function name is case insensitive.
Important: The module prefix of the initialization function name is case sensitive (unlike the function name, which is case insensitive).

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.setDefaultInitializer() 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( cmd 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
Note: 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