# Set constraints on input fields

##### Changed in v12.1.0

`ToggleButton`

has been renamed to `BooleanField`

.

The parametrization constraints can be used for two purposes:

- Dynamic setting of the minimum and/or maximum boundary of a number field
- Dynamic setting of the visibility of an input field

There are four methods of implementing constraints, which are listed in the table below in order of complexity:

method | min/max | visibility |
---|---|---|

static | min=1 | visible=True |

Lookup | min=Lookup('field_x') | visible=Lookup('field_x') |

RowLookup (DynamicArray) | min=RowLookup('field_x') | visible=RowLookup('field_x') |

BoolOperator | N/A | visible=And(Lookup('field_x'), Lookup('field_y')) |

callback function | min=get_min | visible=get_visibility |

A more elaborate example of these methods is given below.

## Static

In the case of a static boundary constraint (e.g. field should always be greater than zero), the numerical value is
simply inserted in the optional `min`

or `max`

argument of the Field.

`param_x = NumberField('X', min=0)`

A field is by default visible, but can be made "hidden" in the interface by directly setting a boolean on the `visible`

argument:

`param_x = NumberField('X', visible=False)`

## Lookup

Sometimes the constraint should be dynamic, such that the evaluation of the constraint depends on the input of one or
more other input fields. For example, `param_y`

should always be larger than `param_x`

. This is achieved using a
`Lookup`

(i.e. looks up the value of the defined field when the constraint is evaluated):

`param_x = NumberField('X')`

param_y = NumberField('Y', min=Lookup('param_x'))

In case of a nested parametrization structure, the dotted path should be used:

`Lookup('tab.section.param_x')`

In a similar way the visibility can be dynamic. Keep in mind that the `Lookup`

in this case should evaluate to a
boolean, and is therefore in practice often used on a `BooleanField`

:

`param_x = BooleanField('X')`

param_y = NumberField('Y', visible=Lookup('param_x'))

When the Lookup cannot find the target field, a warning is raised and the visibility or min/max boundary is set to its
default (i.e. `visible=True`

, `min=None`

, `max=None`

).

## RowLookup

Similar to the `Lookup`

, a `RowLookup`

may be used to set the visibility or boundaries on the min/max of a field in a
`DynamicArray`

. In this way, a field of a specific row within the array can be made dependent of another field **within
the same row**.

`array = DynamicArray('Array')`

array.param_x = NumberField('X')

array.param_y = NumberField('Y', min=RowLookup('param_x'))

## BoolOperator

VIKTOR offers a few specific boolean operators, to make it easy to specify the visibility. These operators evaluate to
a boolean and can therefore **not be used on the min/max** of a field.

The following BoolOperators can be used:

BoolOperator | Can be used to |
---|---|

And | evaluate multiple operands to be True |

Or | evaluate if at least one operand is True |

Not | evaluate an operand to be False |

IsEqual | evaluate two operands to be equal |

IsNotEqual | evaluate two operands to be NOT equal |

IsTrue | evaluate an operand to be True |

IsFalse | evaluate an operand to be False |

IsNotNone | evaluate an operand to be NOT None |

For example, `param_z`

should become visible only when the following conditions are both met:

`param_x`

is equal to False`param_y`

is not equal to 5

`_param_z_visible = And( IsFalse(Lookup('param_x')), IsEqual(Lookup('param_y'), 5))param_x = BooleanField('X')param_y = NumberField('Y')param_z = NumberField('Z', visible=_param_z_visible)`

These boolean operators do not assert truthiness of non-boolean types (e.g. Python may treat an empty string as False, but this will be ignored). Inconsistent types in a boolean operator will raise a warning and if it is used to set the visibility of a field, this will be set to True by default. In a similar way, non-numeric evaluations used to set the min/max boundary of an input field will raise a warning and set the boundary to None by default.

## Callback function

If above boolean operators cannot suffice your needs, specific functions can be created which can contain more complex
logic if necessary. For the purpose of this example, we will implement the same constraint as the previous example. A
callback function works similar to a callback function on the `options`

of an OptionField. The SDK detects when a
custom function is passed, and will evaluate it with the `params`

, `entity_id`

, and `entity_name`

as input. The
example of the boolean operators can be written as a callback function like this:

`def param_z_visible(params, **kwargs): return params.param_x is False and (params.param_y == 5)class Parametrization(ViktorParametrization): param_x = BooleanField('X') param_y = NumberField('Y') param_z = NumberField('Z', visible=param_z_visible)`

##### tip

All individual `kwargs`

can be added explicitly in the signature if needed:

`def param_z_visible(params, entity_id, entity_name, **kwargs):`

...

For constraints that have to be applied to fields within a DynamicArray, make sure that the callback function returns a list of the constraint values, one for each row in the array. Therefore, it is important that the length of this list is equal to the number of rows in an array, otherwise (a warning is logged and) the constraint is ignored:

`def array_param_z_visible(params, **kwargs): return [row.param_x is False and (row.param_y == 5) for row in params.array]class Parametrization(ViktorParametrization): array = DynamicArray('Array') array.param_x = BooleanField('X') array.param_y = NumberField('Y') array.param_z = NumberField('Z', visible=array_param_z_visible)`

When the visibility or min/max depends on data of another entity, the entity_id can be used.

### Truthiness

With Python, it is possible to assert data of different types, for example:

`param_x = True # booleanparam_y = 1 # integerparam_z = 'false' # stringif param_x and param_y and param_z: print('Statement is true') # -> this will be printedelse: print('Statement is false')`

However, this may lead to unexpected behavior in some use cases. In the case of VIKTOR constraints, truthiness of
conflicting types as shown above is not taken into account. Suppose we want to use above listed fields in an `IsEqual`

operator:

`IsEqual(Lookup('param_x'), Lookup('param_y'), Lookup('param_z'))`

this will always result in False, no matter what the inputs of these fields are. If you explicitly like to assert on
truthiness, a custom `FunctionLookup`

may be considered:

`def assert_on_truthiness(param_x, param_y, param_z): return param_x and param_y and param_zFunctionLookup(assert_on_truthiness, Lookup('param_x'), Lookup('param_y'), Lookup('param_z'))`