Live Chat

We'll need to share your messages (and your email address if you're logged in) with our live chat provider, Drift. Here's their privacy policy.

If you don't want to do this, you can email us instead at contact@anvil.works.

Form Validation


Clone

This library provides a module that checks the contents of components, and displays errors if the contents are invalid. It can also disable components such as submit buttons if the form is invalid.

There’s a validation module with a Validator class that performs the validation:

self.validator = validation.Validator()

Here’s how you set up validation for a text field:

self.validator.require_text_field(self.my_text_field, self.label_to_display_if_invalid)

and for a check box:

self.validator.require_checked(self.my_check_box, self.label_to_display_if_invalid)

You can set up validation for any component by using the general-purpose require method.

As well as the component itself, it takes:

  • a list of events that trigger validation
  • a function that returns True if the component is valid, False otherwise
  • the label to display if the field is invalid.
self.validator.require(
  self.my_component,
  ['change', 'lost_focus'],
  lambda component: return component.text != '',
  self.label_to_display_if_invalid,
)

If you want to disable your submit button when the form is invalid:

self.validator.enable_when_valid(self.submit_button)

This sets the enabled property on the component it’s given, so you can use it for any component with an enabled property.

To display the error labels for all invalid fields:

self.validator.show_all_errors()

The Form Validation library is completely free to use, so click on the clone link and use it in your app!

Clone


You can use it from another app by using the App Dependencies dialog.

When you clone the library, you will also get an example app that shows you how to include it and make use of it.

How it works

The validation.Validator class holds data about the validation config in three attributes:

  def __init__(self):
    self._validity = {}
    self._actions = []
    self._component_checks = []

self._validity maps components to a boolean representing whether that component is valid.

self._actions is a list of functions to call that depend on the whole form’s validity. Each function is passed a boolean that’s False if the form is invalid. This is used by the enable_when_valid method to disable buttons, but you could put other functions in this list.

self._component_checks is a list of functions that get called in order when the form is validated.

The require method populates this list with the validation function that you pass into it (named predicate), wrapped in a function that updates the _validity list, displays the error label if necessary, and runs the whole-form checking method (_check):

The require method also sets up event handlers on the component based on the list that was passed into it.

  def require(self, component, event_list, predicate, error_lbl=None, show_errors_immediately=False):

    # When `require` is called, we define a function that wraps `predicate` with some actions to take.
    def check_this_component(**e):
      result = predicate(component)
      self._validity[component] = result
      if error_lbl is not None:
        error_lbl.visible = not result
      self._check()

    # Then register event handlers for the component
    for e in event_list:
      component.set_event_handler(e, check_this_component)
      
    # And add the component check to the Validator's list
    self._component_checks.append(check_this_component)
    
    # Not shown: a bit of code at the end for checking the form as a whole.

require_text_field and require_checked are convenience functions that wrap the require method.

show_all_errors checks the entire form - in practice, this just means iterating over self._component_checks and running each of the functions that were created by require.

There’s also a method for checking the entire form - self.is_valid. This calculates the form’s validity based on the contents of self._validity, so the check functions must be run first if you want the result to be up-to-date.

self._check runs self.is_valid to check if the form is valid, then runs all of self._actions, the actions to be carried out based on the form’s validity.