Widgets using Templates and Schema Properties — flatland 0.8.1 documentation

# Widgets using Templates and Schema Properties

Unlike utilities more directly focused on processing Web forms, Flatland does not include any concept of “widgets” that render a field. It is however easy enough to employ Flatland’s “properties” and markup generation support to build our own widget system. This also gives us complete control over the rendering.

    from flatland import Form, String

    Input = String.with_properties(widget='input', type='text')
    Password = Input.with_properties(type='password')

    class SignInForm(Form):
        username = Input.using(label='Username')
        password = Password.using(label='Password')

## Rendering Widgets with Genshi

Macros via Genshi’s `py:def` directive would be a good way to implement the actual widgets. For example:

    <html
        xmlns:form="http://ns.discorporate.us/flatland/genshi"
        xmlns:py="http://genshi.edgewall.org/"
        py:strip=""
      >

      <py:def
          function="widget(field)"
          py:with="macro = value_of(field.properties.widget + '_widget')"
          py:replace="macro(field)"
        />

      <fieldset py:def="input_widget(field)">
        <form:with
            auto-domid="on"
            auto-for="on"
          >

          <label
              form:bind="field"
              py:content="field.label"
            />

          <input
              form:bind="field"
              type="${field.properties.type}"
            />

        </form:with>
      </fieldset>
    </html>

Typically we would call the `widget` macro manually for each field we want rendered, and in the desired order, but for demonstrative purposes we stub out widgets for each field in arbitrary order:

    <html
        xmlns:py="http://genshi.edgewall.org/"
        xmlns:xi="http://www.w3.org/2001/XInclude"
      >
      <xi:include href="widgets.html"/>
      <body>
        <form>
          ${widget(form['username'])}
          ${widget(form['password'])}
        </form>
      </body>
    </html>

## Rendering with Jinja

If you’re not using Genshi you can still benefit from Flatland’s schema-aware markup generating support. With Jinja we might implement the macros as something resembling this:

    {% set html = form_generator %}

    {% macro widget(field) %}
      {%- set macro = {'input': input}[field.properties.widget] -%}
      {{- macro(field) -}}
    {% endmacro %}

    {% macro input(field) %}
      {%- do html.begin(auto_domid=true, auto_for=true) %}
    <fieldset>
      {{ html.label(field, contents=field.label) }}
      {{ html.input(field, type=field.properties.type) }}
    </fieldset>
      {%- do html.end() %}
    {% endmacro %}

Then we can simply import the `widget` macro to form templates:

    {% from 'widgets.html' import widget -%}
    <html>
      <body>
        <form>
          {{- widget(form['username']) }}
          {{- widget(form['password']) }}
        </form>
      </body>
    </html>

Make sure to add a markup generator to the globals of your Jinja environment:

    from flatland.out.markup import Generator
    jinja_env.globals['form_generator'] = Generator('html')