Responsive disclosure

Revealing parts of a page

Instead of showing a long intimidating page to a user, you can break it up into manageable sections that are revealed only if and when needed.

This example gathers information from someone who wants to make an investment. What you need to fill in is different depending on whether you are a new investor or an existing one. Sections are revealed as you enter information.

Each section optionally contains one or more other sections:

NewInvestmentForm
      |
      |
      +----(InvestorDetailsSection)
                |
                |
                +---(IDDocumentSection)
                |
                |
                +---(AllocationDetailSection)

Optionally displaying a section

NewInvestmentForm is always present:

NewInvestmentForm only.

It optionally contains an InvestorDetailsSection.

Changing the new_or_existing_radio RadioButtonSelectInput refreshes the NewInvestmentForm.

InvestorDetailsSection also showing.

Since you have made a selection using the RadioButtonSelectInput, investment_order.new_or_existing now has a value and the refreshed version of NewInvestmentForm includes the InvestorDetailSection.

Note

The dynamic content example explains how to make an HTMLElement refresh.

class NewInvestmentForm(Form):
    def __init__(self, view):
        super().__init__(view, 'new_investment_form')
        self.enable_refresh()
        self.use_layout(FormLayout())

        if self.exception:
            self.layout.add_alert_for_domain_exception(self.exception)

        investment_order = InvestmentOrder.for_current_session()
        type_of_investor = self.add_child(FieldSet(view, legend_text='Introduction'))
        type_of_investor.use_layout(FormLayout())

        new_or_existing_radio = RadioButtonSelectInput(self, investment_order.fields.new_or_existing, refresh_widget=self)
        type_of_investor.layout.add_input(new_or_existing_radio)

        if investment_order.new_or_existing:
            self.add_child(InvestorDetailsSection(self, investment_order))

The whole picture

The InvestorDetailSection has different contents, depending on whether you chose to be new or existing:

InvestorDetailsSection showing different contents.

The last section, AllocationDetailSection, is only displayed once you agree to the terms inside the InvestorDetailSection.

class InvestorDetailsSection(Div):
    def __init__(self, form, investment_order):
        super().__init__(form.view, css_id='investor_details_section')
        self.enable_refresh()
        self.use_layout(FormLayout())

        investor_info = self.add_child(FieldSet(self.view, legend_text='Investor information'))
        investor_info.use_layout(FormLayout())

        if investment_order.new_or_existing == 'new':
            investor_info.layout.add_input(TextInput(form, investment_order.fields.name))
            investor_info.layout.add_input(TextInput(form, investment_order.fields.surname))
            self.add_child(IDDocumentSection(form, investment_order.id_document))

        elif investment_order.new_or_existing == 'existing':
            investor_info.layout.add_input(TextInput(form, investment_order.fields.existing_account_number))

        self.layout.add_input(CheckboxInput(form, investment_order.fields.agreed_to_terms, refresh_widget=self))
        if investment_order.agreed_to_terms:
            self.add_child(AllocationDetailSection(form, investment_order))