Reputation: 2405
So, I'm designing an html form, which has two input fields.
html template code:
<form role="form" action="/cities/" method="get" autocomplete="on">
<label for="#input1"><strong>Country:</strong></label>
<input id="#input1" type="text" name="country">
<label for="#input2"><strong>State:</strong></label>
<input id="#input2" type="text" name="state">
<input type="submit" value="Go!">
</form>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$.ajax({
url: '/autocomplete',
type: 'GET',
}
}).done(function (data) {
$('#input1').autocomplete({
source: data,
minLength: 2,
});
});
}
</script>
The Flask app has the following route:
@app.route('/autocomplete/', methods=['GET'])
def autocomplete():
country = request.args.get('country')
state = request.args.get('state')
if country:
results = countries_to_states(country)
elif state:
results = state_to_countries(state)
return json.dumps(results)
This is intended to work such that:
If the user enters a partial country name, in the #input1 field, autocompletes the country names. Once the user chooses a country from the autocomplete, it uses this country data to then filter and return possible state values for autocomplete #input2. Similarly, vice versa for when the user enters data into the #input2 field first.
The route code is a bit incomplete, but assume that the filtering happens fine there. What I'm stuck on is the ajax, js code required to get this working. A lot of the code is glued together from other SO answers, but it's mainly broken, since I'm new to JS.
Any ideas? Thanks!
Upvotes: 0
Views: 1927
Reputation: 159905
The issue is that Flask's default content type is text/html
- and jQuery will sniff the returned data's content type (if I recall correctly) to figure out how to handle it if you don't specify what type of data you are getting back from the server. This means that your JSON data is being passed to autocomplete
as a string, rather than a JavaScript object.
The fix on Python's side is to use jsonify
to pass the data back - that will result in the proper application/json
Content-Type
header being returned. You will need to pass your data back in an object since jsonify
doesn't support top-level arrays:
return jsonify(data=results)
On the JavaScript side, you are going to need to make use of the function version of the source
option to extract the data and hand it off to jQuery UI:
function handleAutoComplete(request, resultCallback) {
// Explicitly tell jQuery we expect JSON back
$.getJSON("/autocomplete?country=" + encodeURIComponent(request.term))
// Handle successful responses *and* failures
// to ensure the widget maintains the correct state
.then(function(result) { resultCallback(result.data); })
.fail(function(err) { resultCallback(); });
}
$('#input1').autocomplete({
source: handleAutoComplete,
minLength: 2
});
Upvotes: 1