Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Display wtforms SelectMultipleField display as drop-down and not list

I am using wtforms SelectMultipleField to render a form with a list of choices.

Using a plain vanilla SelectField renders the choices as a drop-down (dropdown).

However, I need to be able to select multiple entries in the list, hence want to use SelectMultipleField. This, however, displays as a listbox (listbox).

This is my code for the form entries: test = SelectMultipleField('test', choices=[(1, 'a'), (2, 'b'), (3, 'c')])

Code to render: <a class="test" id="test">{{ form.test }}</a>

How can I render my SelectMultipleField to display as a dropdown?

like image 414
Håvard Magnussen Avatar asked Jan 29 '26 08:01

Håvard Magnussen


1 Answers

UPDATE: found 'vanilla' solution! Here it is:

A similar question was asked here. I took the base and adjusted it to flask/jinja workflow:

main.py:

from flask import Flask, render_template, request
from flask_wtf import FlaskForm
from wtforms.fields import SelectMultipleField, SubmitField
from wtforms import widgets

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret_key'


choices = [
    'apple',
    'banana',
    'cherry',
]


# This code from WTForms docs, this class changes the way SelectMultipleField
# is rendered by jinja
# https://wtforms.readthedocs.io/en/3.0.x/specific_problems/
class MultiCheckboxField(SelectMultipleField):
    """
    A multiple-select, except displays a list of checkboxes.

    Iterating the field will produce subfields, allowing custom rendering of
    the enclosed checkbox fields.
    """
    widget = widgets.ListWidget(prefix_label=False)
    option_widget = widgets.CheckboxInput()


class Form(FlaskForm):
    global choices
    select_multiple_field = MultiCheckboxField(choices=choices)
    submit = SubmitField()


@app.route('/', methods=['GET', 'POST'])
def index():
    form = Form()

    if request.method == 'POST':
        # Getting selected options
        form_data = form.select_multiple_field.data
        print(form_data)

    return render_template(
        'index.html',
        form=form,
    )


if __name__ == "__main__":
    app.run(debug=True)

index.html:

<!DOCTYPE html>
<html lang="en">

<head>
</head>

<body>

    <style>
        .dropdown-check-list {
            display: inline-block;
        }

        .dropdown-check-list .anchor {
            position: relative;
            cursor: pointer;
            display: inline-block;
            padding: 5px 50px 5px 10px;
            border: 1px solid #ccc;
        }

        .dropdown-check-list .anchor:after {
            position: absolute;
            content: "";
            border-left: 2px solid black;
            border-top: 2px solid black;
            padding: 5px;
            right: 10px;
            top: 20%;
            -moz-transform: rotate(-135deg);
            -ms-transform: rotate(-135deg);
            -o-transform: rotate(-135deg);
            -webkit-transform: rotate(-135deg);
            transform: rotate(-135deg);
        }

        .dropdown-check-list .anchor:active:after {
            right: 8px;
            top: 21%;
        }

        .dropdown-check-list ul.items {
            padding: 2px;
            display: none;
            margin: 0;
            border: 1px solid #ccc;
            border-top: none;
        }

        .dropdown-check-list ul.items li {
            list-style: none;
        }

        .dropdown-check-list.visible .anchor {
            color: #0094ff;
        }

        .dropdown-check-list.visible .items {
            display: block;
        }
    </style>

    <form action="{{ url_for('index') }}" method="POST">
        {{ form.hidden_tag() }}
        <div id="list1" class="dropdown-check-list" tabindex="100">
            <span class="anchor">Select Fruits</span>

            {{ form.select_multiple_field(class="items") }}

        </div>
        {{ form.submit }}
    </form>

    <script>
        var checkList = document.getElementById('list1');
        checkList.getElementsByClassName('anchor')[0].onclick = function (evt) {
            if (checkList.classList.contains('visible'))
                checkList.classList.remove('visible');
            else
                checkList.classList.add('visible');
        }
    </script>

</body>

</html>

enter image description here

==========================================

(this one depends on some JQuery library, but it feels closely to what you are looking for)

link to that library

main.py:

from flask import Flask, render_template, request
from flask_wtf import FlaskForm
from wtforms.fields import SelectMultipleField, SubmitField

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret_key'


choices = [
    'apple',
    'banana',
    'cherry',
]


class Form(FlaskForm):
    global choices
    select_multiple_field = SelectMultipleField(choices=choices)
    submit = SubmitField()


@app.route('/', methods=['GET', 'POST'])
def index():
    form = Form()

    if request.method == 'POST':
        # Getting selected options
        form_data = form.select_multiple_field.data
        print(form_data)

    return render_template(
        'index.html',
        form=form,
    )


if __name__ == "__main__":
    app.run(debug=True)

index.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <link href="https://unpkg.com/[email protected]/dist/multiple-select.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/multiple-select.min.js"></script>
</head>

<body>

    <style>
        select {
            width: 20%;
        }
    </style>

    <form action="{{ url_for('index') }}" method="POST">
        {{ form.hidden_tag() }}
        {{ form.select_multiple_field(**{"multiple": "multiple"}) }}
        {{ form.submit }}
    </form>

    <script>
        $(function () {
            $('select').multipleSelect({
                multiple: true,
                multipleWidth: 60
            })
        })
    </script>

</body>

</html>

enter image description here

==========================================

(feel free to contact me if this answer was not exactly what you are looking for and tell why so, I'll try to adjust it :D)

like image 129
barni Avatar answered Jan 31 '26 20:01

barni