How can I pass data from Flask to JavaScript in a template?
Solution 1:
You can use {{ variable }}
anywhere in your template, not just in the HTML part. So this should work:
<html>
<head>
<script>
var someJavaScriptVar = '{{ geocode[1] }}';
</script>
</head>
<body>
<p>Hello World</p>
<button onclick="alert('Geocode: {{ geocode[0] }} ' + someJavaScriptVar)" />
</body>
</html>
Think of it as a two-stage process: First, Jinja (the template engine Flask uses) generates your text output. This gets sent to the user who executes the JavaScript he sees. If you want your Flask variable to be available in JavaScript as an array, you have to generate an array definition in your output:
<html>
<head>
<script>
var myGeocode = ['{{ geocode[0] }}', '{{ geocode[1] }}'];
</script>
</head>
<body>
<p>Hello World</p>
<button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
</body>
</html>
Jinja also offers more advanced constructs from Python, so you can shorten it to:
<html>
<head>
<script>
var myGeocode = [{{ ', '.join(geocode) }}];
</script>
</head>
<body>
<p>Hello World</p>
<button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
</body>
</html>
You can also use for
loops, if
statements and many more, see the Jinja2 documentation for more.
Also, have a look at Ford's answer who points out the tojson
filter which is an addition to Jinja2's standard set of filters.
Edit Nov 2018: tojson
is now included in Jinja2's standard set of filters.
Solution 2:
The ideal way to go about getting pretty much any Python object into a JavaScript object is to use JSON. JSON is great as a format for transfer between systems, but sometimes we forget that it stands for JavaScript Object Notation. This means that injecting JSON into the template is the same as injecting JavaScript code that describes the object.
Flask provides a Jinja filter for this: tojson
dumps the structure to a JSON string and marks it safe so that Jinja does not autoescape it.
<html>
<head>
<script>
var myGeocode = {{ geocode|tojson }};
</script>
</head>
<body>
<p>Hello World</p>
<button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
</body>
</html>
This works for any Python structure that is JSON serializable:
python_data = {
'some_list': [4, 5, 6],
'nested_dict': {'foo': 7, 'bar': 'a string'}
}
var data = {{ python_data|tojson }};
alert('Data: ' + data.some_list[1] + ' ' + data.nested_dict.foo +
' ' + data.nested_dict.bar);
Solution 3:
Using a data attribute on an HTML element avoids having to use inline scripting, which in turn means you can use stricter CSP rules for increased security.
Specify a data attribute like so:
<div id="mydiv" data-geocode='{{ geocode|tojson }}'>...</div>
Then access it in a static JavaScript file like so:
// Raw JavaScript
var geocode = JSON.parse(document.getElementById("mydiv").dataset.geocode);
// jQuery
var geocode = JSON.parse($("#mydiv").data("geocode"));
Solution 4:
Alternatively you could add an endpoint to return your variable:
@app.route("/api/geocode")
def geo_code():
return jsonify(geocode)
Then do an XHR to retrieve it:
fetch('/api/geocode')
.then((res)=>{ console.log(res) })
Solution 5:
Working answers are already given but I want to add a check that acts as a fail-safe in case the flask variable is not available. When you use:
var myVariable = {{ flaskvar | tojson }};
if there is an error that causes the variable to be non existent, resulting errors may produce unexpected results. To avoid this:
{% if flaskvar is defined and flaskvar %}
var myVariable = {{ flaskvar | tojson }};
{% endif %}