web-dev-qa-db-ja.com

前のフィールドから選択された値を使用して、WTForms選択フィールドに入力します

これに新しく、よく知られているFlaskチュートリアル、Flask-bootstrap、Flask-wtforms、Jinjaなどを使用してアプリをビルドしようとしています。

2つの選択フィールドとボタンがあるフォームがあります。

class Form(FlaskForm): 
    school_year = SelectField('School year', choices=some_tuples_list)
    category = SelectField('Category', choices=[]) 
    submit = SubmitField('submit')

最初のフィールドのみを事前に入力し、他のフィールドには前のフィールドの選択した値に基づいて(クライアント側で)入力します。

テンプレートでは、次のようなものを試します

{{ form.school_year(**{"onchange":"getCategories()"}) }}

正常に動作します(適切なjavascriptとルートを使用して、次のフィールドにデータを入力するためにタプルリストを返すことを条件とします)が、次のようなものが必要です

{{ wtf.form_field(form.school_year(**{"onchange":"getCategories()"})) }}

動作しません(エラー:wtforms.widgets.core.HTMLStringオブジェクトには属性 'flags'がありません)

だから、私の質問は本当に:このwtfフォームフィールドにonChangeイベントを実装するにはどうすればよいのでしょうか。 (そして、これは私がしなければならないことですか、またはビュー機能からの方法がありますか?)

前もって感謝します。

14
fkaralis

以下は、WTFormsのネイティブ機能で動作するこのロジックの実装例です。ここでの秘trickは、WTForms検証を使用する場合、可能なすべての値でフォームをインスタンス化し、Javascriptで使用可能なオプションを変更して、他の選択に基づいてフィルターされた値を表示することです。

この例では、州と郡の概念を使用します(私は多くの地理データを扱っているため、これは私が構築する一般的な実装です)。

フォームは次のとおりです。Javascriptからアクセスするために、重要な要素に一意のIDを割り当てました。

class PickCounty(Form):
    form_name = HiddenField('Form Name')
    state = SelectField('State:', validators=[DataRequired()], id='select_state')
    county = SelectField('County:', validators=[DataRequired()], id='select_county')
    submit = SubmitField('Select County!')

次に、フォームをインスタンス化して処理するためのFlaskビュー):

@app.route('/pick_county/', methods=['GET', 'POST'])
def pick_county():
    form = PickCounty(form_name='PickCounty')
    form.state.choices = [(row.ID, row.Name) for row in State.query.all()]
    form.county.choices = [(row.ID, row.Name) for row in County.query.all()]
    if request.method == 'GET':
        return render_template('pick_county.html', form=form)
    if form.validate_on_submit() and request.form['form_name'] == 'PickCounty':
        # code to process form
        flash('state: %s, county: %s' % (form.state.data, form.county.data))
    return redirect(url_for('pick_county'))

A Flask郡のXHRリクエストに応答するビュー:

@app.route('/_get_counties/')
def _get_counties():
    state = request.args.get('state', '01', type=str)
    counties = [(row.ID, row.Name) for row in County.query.filter_by(state=state).all()]
    return jsonify(counties)

そして最後に、Jinjaテンプレートの下部に配置するJavascript。 Bootstrapについて言及したので、jQueryを使用していると思います。また、これはインラインjavascriptであると想定しているため、エンドポイントの正しいURLを返すためにJinjaを使用しています。

<script charset="utf-8" type="text/javascript">

$(function() {

    // jQuery selection for the 2 select boxes
    var dropdown = {
        state: $('#select_state'),
        county: $('#select_county')
    };

    // call to update on load
    updateCounties();

    // function to call XHR and update county dropdown
    function updateCounties() {
        var send = {
            state: dropdown.state.val()
        };
        dropdown.county.attr('disabled', 'disabled');
        dropdown.county.empty();
        $.getJSON("{{ url_for('_get_counties') }}", send, function(data) {
            data.forEach(function(item) {
                dropdown.county.append(
                    $('<option>', {
                        value: item[0],
                        text: item[1]
                    })
                );
            });
            dropdown.county.removeAttr('disabled');
        });
    }

    // event listener to state dropdown change
    dropdown.state.on('change', function() {
        updateCounties();
    });

});

</script>
26
abigperson

アビグパーソンの答えは私のためにそれを釘付けにした....最終的に。

追加する必要があるのは、画面で何時間も叫ぶ時間を節約できることですが、Webサイトの現在のBootstrap=コードスニペットは、JQueryのスリムバージョンを使用しています。スリムバージョンには、 abigpersonがコードで使用する関数の一部。

JQueryのフルバージョンをスライドすると、すぐに問題が解決しました。

もう少し読むと、BootstrapはjQueryのフルバージョンでうまく機能するので、ゲームを始めましょう。

0
Adam Alexander

PJサントロの答えは素晴らしい。ロード時の更新が呼び出されましたが、最初はイベントリスナーが機能しませんでした。フィールドの状態を参照するキーワードだと思ったので、自分のフィールドIDの「状態」を交換していなかったことが判明しました!ど!したがって、他のオプションを探しているときに、これも機能していることがわかりました。

    // event listener to state dropdown change
$('#state').change(function() {
    updateCounties();
});
0
Vegaskid