Immediate detection of user changes
This section describes the dialogtouched
predefined
action.
Purpose of the dialogtouched
action
The dialogtouched predefined action is a special action that can be used to detect user changes immediately without leaving the current field.
The event is trapped with an ON ACTION dialogtouched
block, to execute code in
your program.
The dialogtouched
action must be enabled/disabled in
accordance with the needs of the dialog: When this action is enabled, the ON ACTION
dialogtouched
block will be invoked each time the user types characters, modifies
the value with copy/paste actions, or uses the widget input helper (like the calendar of a
DATEEDIT
). In client/server mode, this can generate more network traffic as needed.
As soon as the dialogtouched
action is fired, it should be disabled to avoid
un-necessary network round-trips, and it should only be re-enabled when needed.
When the form item type allows value changes to be detected immediately, for example with
COMBOBOX
, CHECKBOX
or DATEEDIT
fields, the
alternative to dialogtouched
to detect field input changes is to use the
ON CHANGE
trigger.
Typical usage of dialogtouched
action
Singular interactive instructions are typically ended with an accept
or
cancel
action. For example, a singular INPUT
statement allows the
end user to enter a database record, and validate or cancel the changes. The INPUT
statement is then re-executed, to enter or modify another record.
Unlike singular dialogs, the DIALOG
instruction can be used continuously for
several data operations, such as navigation, creation, or modification. Typically, the default is
the navigation mode, and as soon as the user starts to modify a field, it switches to edit mode, to
modify a record, or create a new record. Only a user-defined close
or
exit
action will terminate a DIALOG
block. In such case, the
dialog must be notified when the user starts to modify the current record. This can be achieved with
the dialogtouched
predefined action.
What user events fire a dialogtouched
action?
The dialogtouched
action works for any field controlled by the current
interactive instruction, and with any type of form field.
Every time the user modifies the value of a field (without leaving the field), the ON
ACTION dialogtouched
block will be executed, if it is enabled.
The dialogtouched
action can be triggered by typing characters in a text editor
field, using copy/paste, clicking on a CHECKBOX
/ RADIOGROUP
,
moving the cursor of a SLIDER
or changing a date with the calendar of a
DATEEDIT
.
Field value validation when dialogtouched
occurs
When a dialogtouched
action occurs, the current field may contain some text that
does not represent a correct value corresponding to the field data type. For example, a form field
bound to a DATE
variable may contain only a part of a valid date string, such as
"12/24/
". For this reason, the target variable bound to the field cannot hold the
current text displayed on the screen when the ON ACTION dialogtouched
code is
executed, even when using the UNBUFFERED
mode.
To avoid data validation on action code execution, the dialogtouched
action is
defined with validate="no"
attribute in the $FGLDIR/lib/default.4ad action defaults file. This is
mandatory when using the UNBUFFERED
mode; otherwise the runtime would try to copy
the input buffer into the program variable when a dialogtouched
action is
invoked.
Do not define validate="yes"
for the dialogtouched
action,
otherwise non-string data fields will in most cases produce a conversion error, when the user enters
data.
Programming pattern to handle a "save
" button
By default, the dialogtouched
action and navigation actions are enabled.
In the ON ACTION dialogtouched
block, detect the beginning of a record
modification in a DIALOG
block.
To prevent further dialogtouched
action events, disable the action with a DIALOG.setActionActive()
method, disable also navigation actions, and enable the save
action.
Set a flag/status variable to track that the dialog is in edit mode.
When user input is validated and committed in the database, the dialogtouched
and navigation actions can be enabled again, and the save
action can be
disabled.
Set a flag/status variable to indicate that the dialog is back to navigation mode.
In the action handler for the close
or exit
action, which can
be used to close the form, check the status flag to know if the user has started to edit the fields,
and show a warning box before leaving the dialog with EXIT DIALOG
.
Code example:
LAYOUT
GRID
{
Id: [f1 ] Name: [f2 ]
Addr:[f3 ]
}
END
END
ATTRIBUTES
EDIT f1 = FORMONLY.cust_id, NOENTRY;
EDIT f2 = FORMONLY.cust_name;
EDIT f3 = FORMONLY.cust_addr;
END
main.4gl:
PRIVATE DEFINE editing BOOLEAN
MAIN
DEFINE r_cust RECORD
cust_id INTEGER,
cust_name VARCHAR(20),
cust_addr VARCHAR(100)
END RECORD
DEFINE sqlcond STRING
OPEN FORM f1 FROM "form"
DISPLAY FORM f1
DIALOG ATTRIBUTES(UNBUFFERED)
INPUT BY NAME r_cust.* ATTRIBUTES(WITHOUT DEFAULTS)
END INPUT
BEFORE DIALOG
CALL setup_dialog(DIALOG,FALSE)
ON ACTION dialogtouched
CALL setup_dialog(DIALOG,TRUE)
ON ACTION save
MESSAGE "Saving record to database..."
CALL setup_dialog(DIALOG,FALSE)
ON ACTION query
CONSTRUCT BY NAME sqlcond ON cust_name;
ON ACTION close
IF NOT check_close(DIALOG) THEN
NEXT FIELD CURRENT
END IF
EXIT DIALOG
END DIALOG
END MAIN
PRIVATE FUNCTION setup_dialog(d ui.Dialog, e BOOLEAN) RETURNS ()
LET editing = e
CALL d.setActionActive("dialogtouched", NOT editing)
CALL d.setActionActive("save", editing)
CALL d.setActionActive("query", NOT editing)
END FUNCTION
PRIVATE FUNCTION check_close(d ui.Dialog) RETURNS BOOLEAN
IF editing THEN
CALL setup_dialog(d,editing)
RETURN mbox_yn("Do you want to close the form without saving changes?")
END IF
RETURN TRUE
END FUNCTION
PUBLIC FUNCTION mbox_yn(msg STRING) RETURNS BOOLEAN
DEFINE r BOOLEAN
MENU "Question" ATTRIBUTES(STYLE="dialog",COMMENT=msg)
COMMAND "Yes" LET r = TRUE
COMMAND "No" LET r = FALSE
END MENU
RETURN r
END FUNCTION