Forms

First, let’s take a closer look at the code that makes our extension work. Open up AccountDashboard/extension.py and let’s dive in.

When a user selects our form, the Caliper SDK server is called through a special POST request. When a user first hits our form, their request will be sent to the self.default method.

Here’s the code:

async def default(self):
    template = self.get_template('index.html.jinja2', {})

    html = self.get_tecton_form(
        "AccountDashboard",
        custom_template=template,
        routing_key="submit"
    )
    return html

Above, we are generating a Q2Form with the name of our extension as a header: AccountDashboard. Our form renders a custom HTML template, which we’ll discuss further in “Templates”. You’ll also notice a routing_key argument, which we’ll explain in the next step.

For our account dashboard, a great place to start would be to fetch and display a list of the accounts belonging to the active user. Luckily, our request handler has access to this information without us having to do a thing: it is automatically accessible via the self.account_list object.

Here’s the code to obtain our account list. Overwrite your default() method with this one:

async def default(self):
    account_models = []
    for account in self.account_list:
        account_models.append({
            'account_num': account.host_acct_id,
            'account_name': account.product_name,
            'account_balance': account.balance_to_display
        })

    template = self.get_template('index.html.jinja2', {
        'accounts': account_models
    })

    html = self.get_tecton_form(
        "AccountDashboard",
        custom_template=template,
        routing_key="submit"
    )
    return html

Here is the code to display our account list. In AccountDashboard/templates, overwrite your index.html.jinja2 file with this:

<div class="table-wrapper">
    <table>
    <thead>
        <tr>
        <th width="150">
            Host Account ID
        </th>
        <th>
            Account Name
        </th>
        <th class="text-right">
            Account Balance
        </th>
        </tr>
    </thead>
    <tbody>
        {% for account in accounts %}
            <tr>
                <td>{{ account.account_num }}</td>
                <td>{{ account.account_name }}</td>
                <td class="text-right">{{ account.account_balance }}</td>
            </tr>
        {% endfor %}
    </tbody>
    </table>
</div>
<q2-input
        name='account_id'
        id='account_id'
        label="Account ID">
</q2-input>

We start with an empty account_models list, then we iterate through our self.account_list and append an account object to the list with details for each account. The accounts are passed to the custom template, where we can again iterate through the accounts to display the account details.

You’ll notice our input field is still there. It’s not just any field, it’s a q2-input. Tecton components start with q2-, and provide all kinds of benefits from built-in accessibility improvements to consistency with your chosen platform. We’ll use it in the next step.

If you want to make your data look extra nice, add this style block to the top of your index.html.jinja2, above the first <div>:

<style>
    table {
    table-layout: fixed;
    text-align: left;
    }

    td {
    vertical-align: top;
    }

    td,
    th {
    padding: 15px 10px;
    }

    th {
    box-shadow: inset 0 -2px 0 0 #cccccc;
    }

    td {
    box-shadow: inset 0 -1px 0 0 #eeeeee;
    }

    .text-right {
        text-align: right;
    }
</style>

Load up your form again, and make sure it displays your user’s accounts. In the next couple steps, this static form will take an input and respond with data from our database. First, let’s take a look at how the Q2RequestHandler routes requests to different methods.