Data Validation
In the Settings window for input fields, the section for Data Validation has a subsection Numerical validation with settings that allow you to validate user inputs with respect to values. The figure below shows an example of settings for entering a radius.
The Filter options, the Lower bound and Upper bound settings are only visible if the selection in the Unit dimension check combo box is set to one of None, Append unit to number, or Append unit from unit set.
The Value input fields for Lower bound and Upper bound allow you to use global parameters or scalar declaration variables. Using scalar declaration variables in this field supports the same type of data conversions as when using declaration names as a method input argument in a command sequence. This means that scalar Integer and Double declaration variable will always work and scalar String declarations will work if they can be converted to a Double.
Using declaration variable names or global parameters in the Value input fields can only be used when Unit dimension check is set to Append unit to number or Append unit from unit set. In that case, the bounds are checked based on the numerical value entered by the user in the input field. In a Value input field, you cannot use expressions in terms of declared variables but only a single declaration name. If a parameter exists with the same name as a declaration variable, then the value of the global parameter will be used.
The scope of declaration names used in a Value field is limited to the parent form of the input field.
Note that the bounds are updated dynamically as the value of the parameters or declaration variable is changed. This means that several input fields, not actively changed by the user, can fail numerical validation at once caused by a change in another input field, which causes the value of a parameter used in a validation bound to change.
The Error message text field allows you to write a customized error message to be shown when the input values are out of bounds. The error message text can contain eval(variable), which is also allowed in the title for plot groups in the Model Builder. In addition, the Tooltip of the input field allows use of eval(variable). The variable can be the name of any global parameter or scalar declaration. If a parameter and a declaration with the same name exists, then the parameter is used. In addition to parameter and declaration names the special strings MINVALUE and MAXVALUE can be passed to eval and will return the value entered as lower bound or upper bound.
When using eval for a parameter, it will return the evaluated value of the parameter using the same unit that is used to enter the bounds in the Value input field. For a scalar declaration the string value of the declaration is returned which will be true or false for a boolean declaration.
Access to Old Value and New Value in Event Methods
You can create a method for an On data change event directly from the Events section of an input field, as shown in the figure below.
In such a case, the method will automatically get a scalar String input argument with the name newValue, as shown in the figure below.
The variable newValue will get the new value entered in the input field by the user of the app.
In addition to the new value, you may need to access to the old value entered in the input field, for example, to be able to restore it if your custom data validation fails. For this purpose, you can use the event object and its associated methods which are accessible from methods that are called from events. The event object has the following methods:
event.getOldValue()
event.getNewValue()
which return the old and new value, respectively, of the source associated with the form object. The methods return an object called Value which is similar to the DataSource object returned when you call:
app.declaration(<declarationName>)
A DataSource object has the methods getBoolean, getBooleanArray, getBooleanMatrix, getDouble, and so on to allow accessing the value stored in the DataSource object no matter what type it has. It also has the corresponding set methods to allow setting a value. For more information, see Data Source and Declaration.
The Value object is a read-only version of the DataSource object with only the get methods.
Access to Forms and Form Objects in Event Methods
For methods that are called from events, you can access the properties formTag and formObjectTag for the form object that triggered the event. This way, you can access the form object from the event method using the syntax:
app.form(<formTag>).formObject(<formObjectTag>)
To make it more convenient to access the user control that triggered the event there is also a method
event.getUserControl()
that returns the form object, menu item, or ribbon item that triggered the event. The event object is additionally available for methods called from command sequences in, for example, menu items and ribbon items. The interface IPropertyAccess which has methods for getting and setting values on all user interface controls such as form objects, menu items and so on can then be returned by the getUserControl method.
Data Validation from Dialogs
A form that is shown as a dialog can function in two different ways. The first way, which is the default option, works on a copy of the data and stores changes when the user clicks OK in the dialog. The second way is enabled by changing the Store changes value of the form, used as a dialog, from On request to Immediately, as shown in the figure below.
Changes performed in the dialog will then be stored to the associated source variable or parameter immediately and it will work like a regular form in the main application window.
To accomplish storing of the values when the dialog is set to work on a copy, corresponding to the first option above, and store the values on request, the Settings window for a button object has a checkbox Store changes in the section Dialog Actions, as shown in the figure below. When this checkbox is selected, the values in the dialog are stored from the copy used by the dialog to the actual values after the command sequence specified for the button has been run. Part of this command sequence can include a method that performs validation of the data that the user has entered in the dialog. The figure below shows an example of this scenario, with a method validation, for an OK button used in a dialog.
However, this validation approach will not work. This is due to the fact that when the dialog is set to Store changes on request, the values have not yet been stored when the validation method runs since dialog actions such as Store changes are performed after the command sequence for the button has been run. This means that the validation code cannot access the new values to perform a validation on them.
To remedy this, there is an access method that can be used together with form objects such that the value currently entered in them can be used for data validation before they have been stored in their associated source. The syntax for calling this access method is:
app.form(<formTag>).formObject(<formObjectTag>).getValue();
This call will return a Value object, the same type of object described earlier and used for calls to event.getOldValue() and event.getNewValue(). With this type of access to the current value in the form object, a data validation can be performed. The following form object types support the getValue method.
If the user has clicked OK in a dialog and the data validation fails, you typically want to show an error dialog and then leave the dialog open to allow the user to correct the input fields that failed validation. This not possible to achieve using a direct approach since if the OK button is set to have Store changes as a Dialog Action the storing of the data will always be performed after the command sequence, defined in the Settings window of the OK button, has been run.
To remedy this, there is a method for programmatically store changes:
storeChanges(String name)
which will store the changes for a given form, used as a dialog.
Note that you can call:
closeDialog(<dialogTag>)
to close a specific dialog.
When using the technique described above, you can clear the Store changes and Close dialog checkboxes, in the Dialog Actions section for the OK button and instead call storeChanges and closeDialog as part of the flow in the validation method if the validation passes.
Having a way to programmatically store changes also helps with the case where the dialog contains a button that also performs something when closing the dialog, for example, a Compute button. A validation may then be followed by, for example, a compute method. In order to get this compute method to work on the new values entered in the dialog, storeChanges can be called after the data validation has been performed but before the compute method is called.
Example of Data Validation in Forms and Dialogs
This example illustrates the use of data validation in a form and a dialog. This app is very simple and does not fulfill any other function than to demonstrate important aspects of data validation. The app consists of a form with one input field that expects the user to type the string open dialog, as shown in the figure below
If the user types a different string, then an alert window with a message Unknown command is shown:
and the string value for the Command is reset to the default Type open dialog.
If the correct string open dialog is entered, then a dialog opens, as shown in the figures below.
The dialog expects an integer between 1 and 10, in the first input field. In addition, it expects the value in the second input field to be identical to the value in first input field. If all these criteria is fulfilled, no error message is shown and the app starts from the beginning showing the string Type open dialog in the main form.
If the user enters different values, as shown in the figure below:
then an error message is shown with the message The value of y must be equal to x.
When the user now closes the Error message dialog, the user gets a new opportunity to enter matching values in the dialog.
The data validation functionality in this demonstration app is implemented using an On data change event for the Command input field in the main form form1, as shown in the figure below.
The code in method3 shows the user of event.getNewValue and event.getOldValue, as shown below:
String value = event.getNewValue().getString();
String oldValue = event.getOldValue().getString();
if (value.toLowerCase().equals("open dialog")) {
dialog("/form2");
} else {
alert("Unknown command.");
command = oldValue;
}
The dialog form2 has Store changes set to On request, as shown in the figure below.
In the dialog, the value of the variable x is validated in the On data Change event of the input field with label Number x (1-10) and also when clicking the OK button. The y value is only validated when clicking the OK button. The data validations are implemented using the form object access method getValue. The OK button makes use of the storeChanges method. The figure below shows the method run for the On data change event for the input field with label Number x (1-10).
The corresponding code in method2 is as follows:
int valueX = app.form("form2").formObject("inputfield1").getValue().getInt();
if (valueX < 1 || valueX > 10) {
error("The value of x must be greater than or equal to 1 and less than or equal to 10.");
}
The OK button calls method1 for the On data Change event, as shown in the figures below.
The corresponding code in method1 is as follows:
int valueX = app.form("form2").formObject("inputfield1").getValue().getInt();
int valueY = app.form("form2").formObject("inputfield2").getValue().getInt();
method2();
if (valueX != valueY) {
error("The value of y must be equal to x.");
} else {
storeChanges("/form2");
closeDialog("/form2");
command = "Type open dialog";
}