Input validation
There are two types of input validation:
- generic: automatically detected by the platform during user input
- specific: custom logic to handle more complex validation
Both types provide the possibility to mark fields invalid in the interface, which helps users to correct input mistakes.
Generic field constraints
The following constraints are automatically assessed by the platform:
- Numeric min/max boundary
- Non-existing option
- Non-existing coordinate
- Invalid color value
- Invalid date format
When any of these are violated, all actions are blocked until the user fixes the fields (invisible fields are not considered). This way it can be ensured that wrong inputs are never used in one of the calculations. The actions that are blocked are:
- action buttons
- view calculations
- next-button on a Step
When using an SDK version lower than v14, constraints do only block actions when the controller flag
viktor_enforce_field_constraints
is set to True (see U83 for more detail).
The platform currently does not automatically invalidate:
- a selected entity that has been deleted
- a selected file that has been deleted
Numeric min/max boundary
Input value is not within the configured min/max bounds:
NumberField("Number", min=10, max=20) # also on IntegerField / DynamicArray
Non-existing option
The selected option is no longer available, for example due to dynamic options:
OptionField("Please select...", options=dynamic) # also on MultiSelectField / AutocompleteField
Non-existing coordinate
Invalid latitude / longitude pair in a GeoPointField
:
Invalid color value
Invalid value in a ColorField
:
Invalid date format
Format in a DateField
which does not adhere to YYYY-MM-DD:
Specific input validation
Custom logic can be implemented in the application code to handle specific or more complex validation. This is achieved
by means of raising a UserError
, accompanied by the input violations:
import viktor as vkt
def calculate_block_volume(params):
block_width = params.width
block_length = params.length
block_height = params.height
violations = []
if block_width is None:
violations.append(vkt.InputViolation("Input 'width' cannot be empty!", fields=['width']))
if block_length is None:
violations.append(vkt.InputViolation("Input 'length' cannot be empty!", fields=['length']))
if block_height is None:
violations.append(vkt.InputViolation("Input 'height' cannot be empty!", fields=['height']))
if violations:
raise vkt.UserError("Cannot calculate block volume", input_violations=violations)
return block_width * block_length * block_height
A UserError
can be raised on the following actions:
- action buttons
- view calculations
- next-button on a Step
The message defined in the UserError
functions as a generic message to the user, while the message in the
InputViolation
is shown on the field itself and can be more specific:
Multiple fields can be passed to the InputViolation
if the message holds for all of them:
violations.append(InputViolation("Input cannot be empty!", fields=['width', 'length', 'height']))
In case there are multiple issues with a field, multiple messages can be provided:
violations.append(vkt.InputViolation("Message A", fields=['field']))
violations.append(vkt.InputViolation("Message B", fields=['field']))
violations.append(vkt.InputViolation("Message C", fields=['field']))
When you are using a nested parametrisation, you can refer to the field als follows:
violations.append(vkt.InputViolation("Message A", fields=['my_page_name.my_tab_name.field']))
Be careful with marking fields invalid which have dynamic visibility. A user will not be able to fix an invisible field and might be stuck in the validation process!