简体   繁体   English

如何在 Flask WTForms 的 SelectField 中创建“其他”选项?

[英]How to create 'other' option in SelectField in Flask WTForms?

我对 python 和烧瓶还是有点陌生​​,我创建了一个 SelectField,但我希望它像网站有“其他”选项一样,例如,如果一个网站要求性别,它可能有“男性”选项'、'female' 和 'other',当您选择 other 时,系统会提示您输入新的 TextField。我不知道如何在 SelectField 中的选择上执行代码,我只知道如何在提交。

In order to display individual input fields or groups of input fields based on a selected value, the use of JavaScript in connection with a style sheet is necessary.为了根据所选值显示单个输入字段或输入字段组,需要结合样式表使用 JavaScript。

In the following example, a fieldset is displayed as soon as the "Other" option is selected.在以下示例中,只要选择“其他”选项,就会显示一个字段集。 To do this, an EventListener is added to the input field.为此,将 EventListener 添加到输入字段。 If this receives an event, the specific fieldset is selected and enabled based on the name and value of the input field.如果接收到事件,则根据输入字段的名称和值选择并启用特定字段集。 All other fieldsets with a name starting with the selectbox name are disabled.名称以选择框名称开头的所有其他字段集均被禁用。
With the same technique it is also possible to show and hide individual fields.使用相同的技术,也可以显示和隐藏单个字段。

Flask (app.py)烧瓶(app.py)
from enum import Enum, unique
from flask import (
    Flask,
    redirect,
    render_template,
    request,
    url_for
)
from flask_wtf import FlaskForm
from wtforms import SelectField, StringField
from wtforms.validators import DataRequired

app = Flask(__name__)
app.secret_key = b'your secret here'

# Options for the select box.
@unique
class Options(str, Enum):
    OPTION1 = 'Option 1'
    OPTION2 = 'Option 2'
    OPTION3 = 'Other'

# Validate input based on value and name of another field.
class RequiredIf(DataRequired):
    def __init__(self, other_field_name, other_field_value, message=None, *args, **kwargs):
        self.other_field_name = other_field_name
        self.other_field_value = other_field_value
        self.message = message

    def __call__(self, form, field):
        other_field = form[self.other_field_name]
        if other_field is None:
            raise Exception(f'no field named "{self.other_field_name}" in form')
        if other_field.data == self.other_field_value:
            super(RequiredIf, self).__call__(form, field)

class ExampleForm(FlaskForm):
    options = SelectField('Options', choices=[e.value for e in Options])
    options_details = StringField('Details',
        validators=[
            RequiredIf('options', Options.OPTION3.value)
        ]
    )

@app.route('/', methods=['GET', 'POST'])
def index():
    form = ExampleForm(request.form)
    if form.validate_on_submit():
        option = form.options.data
        if option == Options.OPTION3.value:
            option = form.options_details.data
        print(option)
        return redirect(url_for('index'))
    return render_template('index.html', **locals())
HTML (templates/index.html) HTML (模板/index.html)
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style media="screen">
      /* Hide disabled fieldsets. */
      fieldset[disabled] {
        display: none;
      }
    </style>
  </head>
  <body>

    <form method="post">
      {{ form.hidden_tag() }}
      <div>
          {{ form.options.label() }}
          {{ form.options() }}
      </div>

      <fieldset name="options-other">
        <div>
          {{ form.options_details.label() }}
          {{ form.options_details() }}
        </div>
      </fieldset>
      <input type="submit" />
    </form>

    <script type="text/javascript">
      (() => {
        // Register event listener to change the visibility of the fieldset
        // based on the selected option.
        const selectElem = document.querySelector('select[name="options"]');
        selectElem.addEventListener('change', evt => {
          const selected = `${evt.target.name}-${evt.target.value.toLowerCase().replace(' ', '-')}`;
          const selector = `fieldset[name^="${evt.target.name}-"]`;
          document.querySelectorAll(selector).forEach(elem => {
            elem.disabled = !(elem.name && elem.name === selected);
          });
        });

        // Initialize visibility of fieldset after loading.
        const selected = `${selectElem.name}-${selectElem.value.toLowerCase().replace(' ', '-')}`;
        const selector = `fieldset[name^="${selectElem.name}-"]`;
        document.querySelectorAll(selector).forEach(elem => {
          elem.disabled = !(elem.name && elem.name === selected);
        });

      })();
    </script>

  </body>
</html>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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