2016-12-19 17 views
5

nowy na tym, starając się zbudować aplikację po znanej tutorialu kolbie stosując Kolba-bootstrap, kolba-wtforms, Jinja itpzapełnić WTForms wybierz pole używając wartości wybranej z poprzedniego pola

Mam formularz z 2 wybierz pola i przycisk.

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

chcę tylko pierwsze pole być wstępnie wypełnione, a drugi, aby uzyskać zaludnionych (po stronie klienta) w oparciu o wybraną wartość z poprzedniego pola.

W szablonie próbuję coś

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

który działa ok (pod warunkiem, że wrócę listę krotek, aby wypełnić następne pole, stosując właściwą drogę JavaScript i), ale chcę coś jak następuje

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

który nie działa (Error: wtforms.widgets.core.HTMLString obiekt”nie ma atrybutu 'flagi')

Tak, myślę, że moje pytanie naprawdę to: jak zaimplementować zdarzenie onChange w polu formularza wtf? (I czy to jest to, co muszę zrobić, czy jest jakiś sposób z funkcji widoku?)

Z góry dziękuję.

+0

Zarządzam tym z Javascriptem. Interesuje Cię, czy ktoś ma inne rozwiązanie. Pamiętaj, jeśli planujesz użyć formularza.validate_on_submit() w twojej funkcji widoku lista wyborów musi być załadowana z każdą możliwą wartością lub walidacja WTForms zawiedzie. – abigperson

+0

@PJ Santoro Tak, ale jak mogę wywołać JavaScript w polu wtf w szablonie? – fkaralis

+0

Podzielę się poniższym przykładem tego, jak mogę to zaimplementować. – abigperson

Odpowiedz

8

Oto przykładowa implementacja tej logiki do pracy z natywną funkcjonalnością WTForms. Tutaj chodzi o to, że jeśli chcesz użyć walidacji WTForms, musisz utworzyć formularz z każdą możliwą wartością, a następnie zmodyfikuj dostępne opcje w JavaScript, aby wyświetlić przefiltrowane wartości na podstawie innego wyboru.

W tym przykładzie zamierzam użyć pojęcia stanów i hrabstw (pracuję z wieloma danymi geograficznymi, więc jest to powszechna implementacja, którą tworzę).

Oto moja postać, mam przypisane unikalne identyfikatory do ważnych elementów do nich dostęp z javascript:

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!') 

Teraz, widok Kolba do wystąpienia i przetworzyć postać:

@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')) 

Widok kolby odpowiadający na żądania XHR dla hrabstw:

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

I wreszcie cript umieścić na dole twojego szablonu Jinja. Zakładam, że wspomniałeś Bootstrap, że używasz jQuery. Zakładam też, że to jest w linii javascript, więc używam Jinja, aby zwrócić poprawny adres URL dla punktu końcowego.

<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> 
+0

Wydaje się, że wykonuję tę pracę - a także zapewnia bardzo praktyczne wprowadzenie do jQuery. Dziękuję Ci bardzo. – fkaralis

+0

+1 do utworzenia wystąpienia z wszystkimi możliwymi wartościami. Właśnie spędziłem całe wieki próbując dowiedzieć się, dlaczego formularz nie sprawdzi się po aktualizacji opcji JavaScript. Dzięki! –

+0

Używam tego przykładu i otrzymuję błąd NameError: nazwa "State" nie jest zdefiniowana – neilH

0

PJ Santoro odpowiedź jest świetna. Aktualizacja obciążenia została wywołana, ale detektor zdarzeń na początku nie działał. Okazało się, że nie zamieniłem "stanu" na mój własny identyfikator pola, ponieważ myślałem, że to słowo kluczowe odnoszące się do stanu pola! D'oh! Poszukując innych opcji, okazało się, że to zadziałało, może być przydatne dla kogoś tam:

// event listener to state dropdown change 
$('#state').change(function() { 
    updateCounties(); 
}); 
Powiązane problemy