Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

disabling one of the options in WTForms SelectField

What is the simplest way to assign 'disabled' html attribute to one of the options in SelectField in WTForms?

This is my previous code

<select class="form-control" name="division" data-error="Required!" required>
     <option value="default" disabled selected>Select something</option>
     <option value="option1">Option 1</option>
     <option value="option2">Option 2</option>
 </select>

As you can see I would like to set 'disabled' only to first option.

My code for this task is:

next(form.division.__iter__())(**{'disabled':'true'})

And using print function in console I can see the proper output:

<option disabled="true" selected value="default">Select something</option>

The line is working, but somehow this output is not passed to the template. Instead this is what's passed:

<option selected value="default">Select something</option>

Please someone make it clear.

like image 396
MacZel Avatar asked Jun 05 '17 23:06

MacZel


3 Answers

Here's a custom wtforms widget which makes use of the SelectField's Options iterator.

from markupsafe import Markup
from wtforms.widgets.core import html_params


class CustomSelect:
    """
    Renders a select field allowing custom attributes for options.
    Expects the field to be an iterable object of Option fields.
    The render function accepts a dictionary of option ids ("{field_id}-{option_index}")
    which contain a dictionary of attributes to be passed to the option.

    Example:
    form.customselect(option_attr={"customselect-0": {"disabled": ""} })
    """

    def __init__(self, multiple=False):
        self.multiple = multiple

    def __call__(self, field, option_attr=None, **kwargs):
        if option_attr is None:
            option_attr = {}
        kwargs.setdefault("id", field.id)
        if self.multiple:
            kwargs["multiple"] = True
        if "required" not in kwargs and "required" in getattr(field, "flags", []):
            kwargs["required"] = True
        html = ["<select %s>" % html_params(name=field.name, **kwargs)]
        for option in field:
            attr = option_attr.get(option.id, {})
            html.append(option(**attr))
        html.append("</select>")
        return Markup("".join(html))

When declaring the field, pass an instance of CustomSelect as the widget parameter.

division = SelectField(
    "Division",
    choices=[("default", "Select something"), ("option1", "Option 1"), ("option2", "Option 2")],
    validators=[InputRequired()],
    widget=CustomSelect(),
    default="default",
)

And to pass attributes when rendering

form.division(option_attr={"division-0": {"disabled": ""} }, class="form-control")
like image 183
phdesign Avatar answered Oct 17 '22 16:10

phdesign


If you simply just want a disabled and selected option as the first option of your select, I found this to be simpler than extending the SelectField class:

Just loop over the option and check for first loop iteration

<select name="my_select" id="my_select">
    {% for option in form.my_select %}
        {% if loop.first %}
            <option value="" disabled selected>select something</option>
        {% endif %}
        {{ option }}
    {% endfor %}
</select>
like image 20
Carson Evans Avatar answered Oct 17 '22 16:10

Carson Evans


When you disable the field the values are no longer passed. What you might want to do is pass the variable by using read only instead of disabled. Here's how do to it with jquery :

$('#id_of_option').prop('readonly', true);

Also what I've done is set choices in Wtforms where

choices = [('', 'please select an option'), ('1', 'option 1'),  ('2', 'option 2')]

and this way a user has to select a value.

like image 1
timmyjl12 Avatar answered Oct 17 '22 17:10

timmyjl12