I'm using Flask with Jinja2 templates, how can I make dependent select pox using Jinja2 or using Java script + Jinja2 variable?
Example:
Python side:
@app.route('/')
def dependent():
cars= {'Chevrolet':['Volt','Malibu','Camry'],'Toyota':['Yaris','Corolla'],'KIA':['Cerato','Rio']}
return render_template('select.html',cars=cars)
HTML+Jinja side
<form>
<select name="car_vendor" id="car_vendor">
{% for key, value in cars.items() %}
<option value="{{ key }}"> {{ key }} </option>
{% endfor %}
</select>
<select name="car_model" id="car_model">
---
---
</select>
</form>
How can I populate car_model select box dependently on the car_vendor select box like in the picture:
PS: I'm completely ignorant regarding JS, jQuery and Ajax, I've seen many JS or jQuery examples and I was like a man lost and paralyzed in the desert, So please if you're going to help, edit my code example and don't link me to external links. Thanks in advance.
First, you need to specify which car vendor and model have been selected to determine how the dependent select box should be populated:
cars = {'Chevrolet':['Volt','Malibu',Camry],'Toyota':['Yaris','Corolla'],'KIA':['Cerato','Rio']}
return render_template('select.html',cars=cars, selected_car='Toyota', selected_model = 'Prius')
Second, for the first select box you should just be enumerating keys rather than items since you have no use for the dictionary's values. What you are doing "works" but is less clear. You should be setting the selected
property of the option that has been selected:
<select name="car_vendor" id="car_vendor">
{% for key in cars.keys() %}
<option value="{{ key }}" {% if key == selected_car %}selected="selected"{% endif %}> {{ key }} </option>
{% endfor %}
</select>
Finally, the car model that has been selected determines which set of models to populate the dependent select box with:
<select name="car_model" id="car_model">
{% for model in cars[selected_car] %}
<option value="{{ model}}" {% if model == selected_model %}selected="selected"{% endif %}> {{ model}} </option>
{% endfor %}
</select>
<form>
Now the above assumes there is always a car and car model selected. You might start out with no selections where selected_car
and selected_model
are both None
. To support this, the first select box should have an initial tag:
<option value=''>*** Select a car make ***</option>
This will be selected by default if no other option as the selected
attribute set. (You can and should add a similar option to the second select box.) And since selected_car
is None
, you need to surround the second select box with a test for this:
{% if selected_car %}
<select name="car_model" id="car_model">
etc.
{% endif %}
And so the second text box will not be shown until there is a selection in the first box.
But you must always make sure that when there is a selection change in the first box, that the form is submitted and the new selection can be reflected in the second box. So you need to add to the first select box:
<form name="f">
<select name="car_vendor" id="car_vendor" onchange="document.f.submit();">
Update: Sample Flow
car_vendor
nor car_model
is set. Consequently the template is invoked with both template variables selected_car
and selected_model
set to None
. This results in the car vendor select box being populated with no selection and the car model select box not being displayed.car_vendor
set to 'Toyota' and car_model
not set and so template variables selected_car
is set to Toyota
and selected_model
being set to None
. This results in the car model select box displaying Toyota as the currently selected car and the car model select box being displayed with all the Toyota models but with no current selection.car_vendor
set to 'Chevrolet' and car_model
not set and so template variables selected_car
is set to Chevrolet
and selected_model
being set to None
. This results in the car model select box displaying Chevrolet as the currently selected car and the car model select box being displayed with all the Chevrolet models but with no current selection.car_vendor
set to 'Chevrolet' and car_model
set to 'Camry' and so template variables selected_car
is set to Chevrolet
and selected_model
id set to Camry
. This results in the car model select box displaying Chevrolet as the currently selected car and the car model select box being displayed with all the Chevrolet models and 'Camry' as the current selection. In addition, whatever processing and output is performed now that both a vendor and model have been selected. Note that now if a new vendor is selected, the current model will first be de-selected before the form is submitted to ensure that a model that belongs to a different vendor is not sent up with the form. This is the reason for clearing the car model selection when a new car vendor is selected.Sample Code Based on Sample Flow (more or less)
from flask import Flask, request, render_template_string
app = Flask(__name__)
@app.route('/', methods=['POST', 'GET'])
def dependent():
cars = {'Chevrolet':['Volt','Malibu','Camry'],'Toyota':['Yaris','Corolla'],'KIA':['Cerato','Rio']}
# look for data from form POST (won't be present when we are invoked with GET initially)
selected_car = request.form['car_vendor'] if 'car_vendor' in request.form else None
if not selected_car or selected_car not in cars:
selected_car = None
selected_model = None
else:
selected_model = request.form['car_model'] if 'car_model' in request.form else None
# This is an alternative to unselecting the car model whenever a new car vendor is selected.
# Instead, we just check whether the selected model belongs to the selected car vendor or not:
if selected_model and selected_model not in cars[selected_car]:
selected_model = None
# Use a string template for demonstration purposes:
return render_template_string("""
<!DOCTYPE html>
<html>
<head>
<title>Flask Demo</title>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0">
</head>
<body>
<h2>Select Car</h2>
<form name="f" method="post">
<table>
<tr>
<th>Make</th>
<th>Model</th>
</tr>
<tr>
<td>
<select name="car_vendor" id="car_vendor" onchange="document.f.submit();">
{% if not selected_car %}
<option value=''>-- Select a Make --</option>
{% endif %}
{% for car in cars.keys() %}
<option value="{{ car }}" {% if car == selected_car %}selected="selected"{% endif %}>{{ car }}</option>
{% endfor %}
</select>
</td>
<td>
{% if selected_car %}
<select name="car_model" id="car_model" onchange="document.f.submit();">
{% if not selected_model %}
<option value=''>-- Select a Model --</option>
{% endif %}
{% for model in cars[selected_car] %}
<option value="{{ model }}" {% if model == selected_model %}selected="selected"{% endif %}>{{ model }}</option>
{% endfor %}
</select>
{% endif %}
</td>
</tr>
</table>
</form>
{% if selected_car and selected_model %}
<p style="color: red;">Both make and model have been selected: {{ selected_car }} and {{ selected_model }}.</p>
{% endif %}
</body>
</html>
""", cars=cars, selected_car=selected_car, selected_model=selected_model)
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.