Customizable Wizard Interface

I needed a way to display multiple forms in an alert in sequence, like a typical wizard interface, so I wrote a wizard form to handle the grunt work. Posted here in the hopes it’ll be useful for someone else: Anvil | Login

If you just want to see how it works, here’s the link to the most current version: https://honest-trusty-airport.anvil.app

There’s basic support for validation of each step of the wizard, and aggregating the results at the end. You can also hook actions in the steps up to the next button, e.g. hitting Enter in a text field can automatically move to the next step.

Edit: I’ve added enough customization that some documentation seems warranted.

Showing The Wizard

Create an instance of the wizard component by passing it a list of forms that make up the steps. Call the show method and if it returns True, that means the user finished the wizard:

    from Wizard_Component.Wizard import Wizard

    wizard = Wizard(item=steps)
    
    if wizard.show():
      print(wizard.get_data())

To prevent the user from cancelling the wizard, pass in allow_cancel=False:

    wizard = Wizard(item=steps, allow_cancel=False)

Steps That Provide Information Only

The most basic step is a blank panel form that provides the user with information only. It needs nothing extra beyond the labels that display the information.

Steps That Take User Input

A step that takes user input must implement the get_data method:

  def get_data(self):
    return {'real_name': self.text_box_1.text, 
            'use_nickname': self.use_nickname.checked}

Steps Where The User Can Enter Invalid Input

In steps where the user might enter something invalid, the step can use the validate method to let the wizard know if the data in it is valid. Steps must display their own error messages.

  def validate(self):
    self.error_label.visible = not self.text_box_1.text
    return bool(self.text_box_1.text)

Steps That Might Be Skipped

A step that might not show must implement the pre_show method to tell the wizard whether the step should be shown, based on the data entered in previous steps:

  def pre_show(self, data):
    # Only show this step if they are a customer
    return data['role'] == 'customer'

Steps That End The Wizard Early

If you have a branching set of steps, a step in the middle of the list might be the end of one branch. That step must set final_step to True to tell the wizard that it’s the ending step of its branch.

  def __init__(self, **properties):
    self.init_components(**properties)
    
    self.final_step = True

Steps That Need To Customize The Next/Finish Button

Especially with branching sequences, the text “Finish” might not be appropriate for every final step. A step can customize the text that appears in the Next/Finish button by setting the next_text property:

  def __init__(self, **properties):
    self.init_components(**properties)
    
    self.next_text = "Start Using The Site"
    self.final_step = True

Events Steps Can Use

There are events that steps can use to communicate back to the wizard:

x-next allows a step to programmatically trigger the Next button click. Useful if your step has a single text box, to allow the user to press Enter to continue.

  def text_box_1_pressed_enter(self, **event_args):
    self.raise_event('x-next')

x-data allows a step to get the current state of the wizard’s data. This cannot be used in the __init__ method of the step, since the wizard has not added the event to the step yet.

data = self.raise_event('x-data')

Adjusting Step Form Based On Data

The normal way to adjust the content on the step form based on the current data would be to add a pre_show method, use the data parameter to modify the look of the form, and then return True. That all happens before the form is visible.

6 Likes

This is awesome! I was going to build something like this but you beat me to it. Beautiful.

1 Like

Glad you found it useful! It’s totally undocumented at the moment, but the sample steps in the app show all the features, including skipping steps as needed.

Edit: no longer undocumented. I added info to the original post about how to use the wizard. It’s been updated to support branching paths through the steps, with multiple ending steps.

2 Likes

That’s awesome.

I’m going to start working on creating a “Step Creator” component within the wizard to give the option to users to create steps and persist them to the database, along with the standard programmatic way of defining steps.

1 Like

There was a bug when the wizard was cancelled, and you tried to add the same step instances to a different wizard. That’s been fixed now.