简体   繁体   中英

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.

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.

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")

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>

This worked for me.

<select id="{{ form.my_select.id }}" name = "{{ form.my_select.name }}">
    {% for option in form.my_select %}
        {% if loop.first %}
            {{ option(disabled="") }}
        {% else %}
            {{ option }}
        {% endif %}
    {% endfor %}
</select>

The HTML 'disabled' attribute is a boolean one and in regular HTML, it does not need to be assigned to "". Without the equal sign, I got some positional argument errors.

If you want to disable other options (say, 4th and 5th option in addition to the first one), you can do this:

<select id="{{ form.my_select.id }}" name = "{{ form.my_select.name }}">
    {% for option in form.my_select %}
        {% if loop.first %}
            {{ option(disabled="") }}
        {% elif loop.index == 4 or loop.index == 5 %}
            {{ option(disabled="") }}
        {% else %}
            {{ option }}
        {% endif %}
    {% endfor %}
</select>

Note that loop.index is 1-based.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM