Skip to content

Data binding and validation

In A form that does something every field was read and checked by hand. Here the controls do that work themselves: each one is bound to a field of the form’s data, carries its own rules, and shows its own error message. The Python left to write is a single if.

Goal Time Level You need
A sign-up form that validates itself 25 minutes Intermediate · a little Python A form that does something
  • Bind an input to a field of form.data (two-way: it shows the field and writes back what the user types).
  • Show a live expression in a label (f"Nice to meet you, {name}!").
  • Add rules: required, a pattern, a minimum length, a minimum number, your own message.
  • Validate everything with form.validate(), and read form.data and form.errors.
The sign-up form with an invalid email, a short password and the terms unchecked, each with its message
Each control checks its own rules and shows the message under itself.
  1. Draw the form. A new form named signup with a Heading, a Label named greeting, three Text boxes (your_name, email, password, the last with Password switched on), a Number box named age, a Check box named terms (text I accept the terms), a small label summary, a label status and a Button named create.

  2. Bind the inputs. Select your_name and, in the Data section of Properties, type name in Bind to. Do the same for the others:

    Control Bind to Rules (Data section)
    your_name name Required
    email email Required, Pattern [^@\s]+@[^@\s]+\.[a-z]{2,}, Message Enter a valid email
    password password Required, Minimum length 8
    age age Minimum 13, Message You must be 13 or older
    terms terms Required (a check box passes only when checked), Message Please accept the terms
    The Data section of a text box: Bind to, Required, Pattern and Message
    The Data section: the field the control is bound to and its rules.
  3. Show a live expression. A display control (label, heading, badge…) can bind to a Python expression over the data, recomputed on every redraw. Select greeting and set Bind to:

    f"Nice to meet you, {name}!" if name else "Fill in the form below."

    And summary:

    f"{len(password)} characters in your password"
  4. Run it (F5) and type. The greeting follows your name letter by letter, and each input checks its rules as you type: a red border and a message bubble under it.

  5. Validate on click. Double-click create and write the handler:

    def create_click(form, event):
    if not form.validate(): # checks every rule and shows every message
    form.status.color = "error"
    form.status.text = f"{len(form.errors)} field(s) need your attention."
    return
    data = form.data # {"name": ..., "email": ..., "age": 18, "terms": True, ...}
    form.status.color = "success"
    form.status.text = f"Welcome aboard, {data['name']}!"

    form.data is a plain dict filled by the bound controls. Save it, send it to an API or pass it to another form.

signup.pzform holds the layout, the bindings and the rules; signup.py only the button:

examples/tutorial/designer/signup.py
"""Event handlers for the sign-up form (tutorial: Data binding and validation).
pyzed run examples/tutorial/designer/signup.pzform
The controls are bound to fields of ``form.data`` (Properties → Data → Bind to) and carry their
validation rules, so the handler only has to call ``form.validate()`` and read ``form.data``.
"""
def create_click(form, event):
"""Runs when create is clicked."""
if not form.validate(): # checks every rule and shows the messages under the controls
form.status.color = "error"
form.status.text = f"{len(form.errors)} field(s) need your attention."
return
data = form.data # {"name": ..., "email": ..., "password": ..., "age": ..., "terms": True}
print("New account:", {k: v for k, v in data.items() if k != "password"})
form.status.color = "success"
form.status.text = f"Welcome aboard, {data['name']}!"
Windows, macOS and Linux
uv run --with pyzed-ui pyzed run examples/tutorial/designer/signup.pzform
Validation at work in the sign-in example: a wrong email is flagged as you type and clears once fixed.

Bound controls need almost no events: each change goes into form.data by itself. The form has one handler, create_click, which calls form.validate() and reads form.data.

def form_load(form, event): # start in the first box
return form.name.focus()
def terms_change(form, event): # a check box: event.value is True or False
form.create.enabled = event.value
def email_change(form, event): # check one field as the user types
form.email.validate() # shows (or clears) its message right away