1
votes

I've been struggling for nearly a day on a simple rendering of a form field. That would be great if you could help me on this one.

I'm using Flask-WTF, python 2.7.

I'm trying to render a SelectField using a custom ListWidget. The field basically must be rendered within a UL HTML tag, rather than a SELECT html tag, and this seems to be what I'm struggling with.

This is how my custom widget class is:

widget.py

class CustomListWidget(ListWidget):

    def __init__(self, *args, **kwargs):
        super(CustomListWidget, self).__init__(*args, **kwargs)

    def __call__(self, field, **kwargs):
        kwargs.setdefault('id', field.id)
        html = ['<{} {}>'.format(self.html_tag, html_params(**kwargs))]
        for subfield in field:
            html.append('<li><span>{}</span></li>'.format(subfield()))
        html.append('</{}>'.format(self.html_tag))
        return HTMLString(''.join(html))

This is how my form looks, and the category field is the one I'm struggling with.

form.py

from widget import CustomListWidget
from wtforms import SelectField, SubmitField


widget = CustomListWidget(html_tag='ul')

class MyForm(Form):
    category = SelectField('category', [DataRequired()], widget=widget, default='1', choices=[
        ('1', 'whatever'),
        ('2', 'whatever2')
    ])
    submit = SubmitField('Search')

view.py

from form import MyForm
from flask import render_template

@app.route('/formtest', methods=['GET', 'POST'])
def formtest():
    form = MyForm()
    if request.method == 'GET':
        render_template('form.html', form=form)

    if form.validate_on_submit():
        return redirect(url_for('whatever', data=-form.data))
    return 'form not validated'

form.html

<div class="search-input with-dropdown">
    <div class="dropdown">
       {{ form.category(class='dropdown-content hide') }} }}
    </div>
</div>

With this code I'm able to get the display expected, but no value are being passed from the field. Whichever value I select, after I submit, only the default value is there.

1

1 Answers

2
votes

I've done something similar recently with a loop to iterate over all the choices. Basically, I've created a SelectMultipleField copy to have my own html for it as we needed specific stuff.

As you can see in the snipped in bellow, I iterate over the field.iter_choices().

{%- if field.type in ['SelectMultipleField'] %}
    <ul>
    {% for key, value, checked in field.iter_choices() %}
        <li>{{ value }}</li>
    {% endfor %}
    </ul>
{%- endif %}

You can read more about custom widgets in http://wtforms.simplecodes.com/docs/0.6/widgets.html