Martijn Rutten
Martijn Rutten

Reputation: 781

Append form from template using WTForms FieldList and Ajax

I am trying to create a dynamic form (within a python Flask application) using WTForms.

WTForms includes a FieldList field for lists of fields. I'd like to use this to make a form where users can add or remove items, e.g. specify different phone numbers.

Here is an example of a WTF solution using Ajax with WTForms and related question. These clone an existing form, and hence only work if there is at least one instance of the form already. I would like to remove this constraint to also allow an initially empty form.

I would like to use a javascript form plugin called SheepIt to dynamically add/remove widgets which does allow this, using a "form template" in the html.

Question is how to replace custom html in the "form template" such as:

<input id="phoneForm_#index#_number"
name="user[phones][#index#][number]" type="text"

with a WTF form field such as:

{% for phone in form.phones %}
  {{ phone.number }}
{% endfor %}

that allows the WTF goodies such as printing of form validation errors, etc. Problem here is I do not know if/where to place the above for loop when using a "template form" as done in SheepIt.

Upvotes: 3

Views: 3413

Answers (1)

iodbh
iodbh

Reputation: 708

Flask's documentation suggests the following jinja2 macro for rendering WTForms fields:

{% macro render_field(field) %}
  <dt>{{ field.label }}
  <dd>{{ field(**kwargs)|safe }}
  {% if field.errors %}
    <ul class=errors>
    {% for error in field.errors %}
      <li>{{ error }}</li>
    {% endfor %}
    </ul>
  {% endif %}
  </dd>
{% endmacro %}

To render subfields in a fieldlist, I use a slightly different version of this macro:

{% macro render_multi_field(field,field_name) %}
    <div class="form-group">
        {{ field_name }}
        {% for subfield in field %}
        <div class="base_class{% if subfield.errors %} error_class{% endif %}" id="{{subfield.name}}-group">
            {{ subfield(**kwargs)|safe }}
            <button data-field="{{ subfield.name }}-group">Remove Entry</button>
        </div>
        {% if subfield.errors %}
             {% for error in subfield.errors %}
                <p class="error_class">{{ error }}</p>
            {% endfor %}
        {% endif %}

        {% endfor %}
        <br/>
        <button type="button">Add entry</button>
    </div>
{% endmacro %}

I use this macro to render Fields with 0 to any number of entries. It allows error rendering, populating with default values and anything else you'd do with WTForms.

In my case, widgets are added / removed by javascript via the button in the macro.

Upvotes: 2

Related Questions