The SUBDIALOG clause
Purpose of SUBDIALOG
The SUBDIALOG
clause defines a declarative dialog to be attached to the
current procedural DIALOG
block.
By using form inclusion (with the FORM
clause in LAYOUT
sections) and declarative dialogs + SUBDIALOG
, you enforce code reusability in your
application sources.
Defining the declarative dialog
The declarative dialog is implemented outside the scope of the using DIALOG
block, at the same level as a function.
The declarative dialog can be defined in a different module, to be reused in other
DIALOG
instructions. The sub-dialog module must be imported with the IMPORT FGL
instruction.
Like other module elements such as functions and reports, the name specification is mandatory
when defining a declarative dialog. The name of the declarative dialog will be referenced in a
SUBDIALOG
clause of a procedural dialog instruction.
In the "comment.4gl" module:
DIALOG comment_input()
...
END DIALOG
IMPORT FGL comment
...
FUNCTION mydialog()
DIALOG ...
...
SUBDIALOG comment.comment_input
...
END DIALOG
END FUNCTION
Sub-dialogs in form definitions
Implementing a sub-dialog as a declarative dialog in a separate module is typically used in
conjunction with the FORM clause, in the
LAYOUT
section of form specification files:
LAYOUT
...
FORM "comment"
...
END
Semantics with SUBDIALOG
In terms of semantics, behavior and control block execution, a declarative dialog attached to a
procedural dialog with SUBDIALOG
, behaves like a sub-dialog that is defined inside
the procedural DIALOG
block.
For example, BEFORE INPUT
inside an INPUT
block of a declarative dialog will be executed when the focus goes
to one of the fields of that sub-dialog.
Scope of dialog instructions
Other sub-dialogs can reference the attached declarative dialog in the current scope.
NEXT
FIELD
instruction referencing a field in another
sub-dialog:DIALOG ... -- Parent dialog block
...
NEXT FIELD the_comment -- Field of the declarative dialog.
...
END DIALOG
Scope of DIALOG keyword
DIALOG
keyword inside a declarative dialog block to use
ui.Dialog
class methods, it references the current procedural dialog
object:DIALOG comment_input()
...
CALL DIALOG.setFieldActive("the_comment",TRUE)
...
END DIALOG
Writing generic code
To be reused by different procedural DIALOG
instructions, the code of
sub-dialog modules must be generic. However, if the sub-dialog code needs to interact with
the parent DIALOG
, it must be possible to call a function from the parent
DIALOG
.
You achieve this by using function references. Parent modules can then configure the sub-dialog module at runtime, with callback functions:
- Create a user-defined
TYPE
with theFUNCTION
type matching the callback function of the using module. - Define a module variable, with the declared function type. If you want to keep it private to the module, define a setter function to assign the variable with the callback function reference.
- When the parent
DIALOG
needs to be notified by some change in the sub-dialog, check that the callback variable is notNULL
, and call the function with appropriate values.
DIALOG
, that something happened in the
sub-dialog. The parent DIALOG
can then query the sub-dialog module
for more information, as long as the sub-dialog module provides functions to query
its status. PUBLIC TYPE cb_comment_event FUNCTION (event STRING)
PRIVATE DEFINE cb_ce cb_comment_event
...
PUBLIC FUNCTION set_event_callback(f cb_comment_event)
LET cb_ce = f
END FUNCTION
DIALOG comment_input()
...
IF cb_ce IS NOT NULL THEN
CALL cb_ce("comment_changed")
END IF
...
END DIALOG
For a complete example, see Example 3: DIALOG with SUBDIALOG.