Flask how to pass list of list to javascript [duplicate] - python

I am trying to pass data as JSON from a Flask route to a Jinja template rendering JavaScript. I want to iterate over the data using JavaScript. The browser shows SyntaxError: Unexpected token '&'. Expected a property name. when JSON.parse is called on the rendered data. How do I use rendered JSON data in JavaScript?
var obj = JSON.parse({{ data }})
for (i in obj){
document.write(obj[i].text + "<br />");
}
def get_nodes(node):
d = {}
if node == "Root":
d["text"] = node
else:
d["text"] = node.name
getchildren = get_children(node)
if getchildren:
d["nodes"] = [get_nodes(child) for child in getchildren]
return d
tree = get_nodes("Root")
return render_template("folder.html", data=tree)
If I just put {{ data }} in the HTML part, what I see looks correct.
{'text': 'Root', 'nodes': [{'text': u'Prosjekt3'}, {'text': u'Prosjekt4', 'nodes': [{'text': u'mappe8'}]}]}

Flask's Jinja environment automatically escapes data rendered in HTML templates. This is to avoid security issues if the dev tries to render untrusted user input.
Since you are passing a Python object to be treated as JSON, Flask provides the tojson filter which automatically dumps the data to JSON and marks it safe.
return render_template('tree.html', tree=tree)
var tree = {{ tree|tojson }};
When you just look at the data rendered in HTML, it looks correct because the browser displays the escaped symbols as the real symbols (although in this case you're seeing the string representation of a Python dict, not JSON, so there's still some issues like u markers).
Previous versions of Flask didn't mark the dumped data safe, so you might come across examples like {{ tree|tojson|safe }}, which isn't required anymore.
If you're not rendering JSON (or you already dumped the JSON to a string), you can tell Jinja that data is safe to render without escaping by using the safe filter.
# already dumped to json, so tojson would double-encode it
return render_template('tree.html', tree=json.dumps(tree))
var tree = {{ tree|safe }};
You can also wrap the string in Markup before rendering it, it's equivalent to the safe filter.
# already dumped and marked safe
return render_template('tree.html', tree=Markup(json.dumps(tree)))
var tree = {{ tree }};
If you're not passing this data to JavaScript, but using it in Jinja instead, you don't need JSON. Pass the actual Python data, don't call tojson on it, and use it as you would any other data in the template.
return render_template('tree.html', tree=tree)
{% for item in tree %}
<li>{{ item }}</li>
{% endfor %}

I could archive it using the following code sample.
<script>
console.log(JSON.parse({{json|safe}}))
</script>

The problem is that your server returns not JSON, but rendered HTML, which escapes some of the symbols with & notation.
Instead of using
return render_template("folder.html", data=tree)
try
return flask.jsonify(**tree)

Related

How to use Python Flask variables in Javascript

I have a Python variable whose value is a string of text and would like to edit that value via Javascript.
I have no idea how to go about doing this.
Attempts:
function changeValue(val) {
val = 'new text';
}
<textarea placeholder="some text">{{ changeValue({{ result }}) }}</textarea>
<textarea placeholder="some text">
{{ result }}
</textarea>
What I want: I have some text (result) being added and would like to check if the text is empty. If so, I want to show the placeholder text.
The issue: Although I can check if the value is empty, when I try to print that result out it reads none
Thanks to all!
You do not need to call the JavaScript function from the HTML file. There are several approaches you can take:
1. Store the variable in HTML metadata:
<meta id="result_var" data-result={{result}}>
And then get the data in JavaScript:
result = document.getElementById("result_var").value;
2. Keep the variable in the tag where it's supposed to be and get it from there in JavaScript:
<textarea placeholder="some text" id="result-var"> {{result}} </textarea>
And then get it in JavaScript:
let result = document.getElementById("result-var");
3. Query it from your API: You can create a route in your Flask app that returns JSON data with the variable you need and then get that data to your JavaScript file by sending a request to your API.
4. Jinja format: I've seen solutions that involve just using the variable as if it was a jinja variable in JavaScript like this: let result = JSON.parse('{{ result | tojson }}');. But I haven't been able to get this working properly, not sure why.
I hope this helps!

Passing in variable template inputs for render_template() (Flask) [duplicate]

I am trying to pass data as JSON from a Flask route to a Jinja template rendering JavaScript. I want to iterate over the data using JavaScript. The browser shows SyntaxError: Unexpected token '&'. Expected a property name. when JSON.parse is called on the rendered data. How do I use rendered JSON data in JavaScript?
var obj = JSON.parse({{ data }})
for (i in obj){
document.write(obj[i].text + "<br />");
}
def get_nodes(node):
d = {}
if node == "Root":
d["text"] = node
else:
d["text"] = node.name
getchildren = get_children(node)
if getchildren:
d["nodes"] = [get_nodes(child) for child in getchildren]
return d
tree = get_nodes("Root")
return render_template("folder.html", data=tree)
If I just put {{ data }} in the HTML part, what I see looks correct.
{'text': 'Root', 'nodes': [{'text': u'Prosjekt3'}, {'text': u'Prosjekt4', 'nodes': [{'text': u'mappe8'}]}]}
Flask's Jinja environment automatically escapes data rendered in HTML templates. This is to avoid security issues if the dev tries to render untrusted user input.
Since you are passing a Python object to be treated as JSON, Flask provides the tojson filter which automatically dumps the data to JSON and marks it safe.
return render_template('tree.html', tree=tree)
var tree = {{ tree|tojson }};
When you just look at the data rendered in HTML, it looks correct because the browser displays the escaped symbols as the real symbols (although in this case you're seeing the string representation of a Python dict, not JSON, so there's still some issues like u markers).
Previous versions of Flask didn't mark the dumped data safe, so you might come across examples like {{ tree|tojson|safe }}, which isn't required anymore.
If you're not rendering JSON (or you already dumped the JSON to a string), you can tell Jinja that data is safe to render without escaping by using the safe filter.
# already dumped to json, so tojson would double-encode it
return render_template('tree.html', tree=json.dumps(tree))
var tree = {{ tree|safe }};
You can also wrap the string in Markup before rendering it, it's equivalent to the safe filter.
# already dumped and marked safe
return render_template('tree.html', tree=Markup(json.dumps(tree)))
var tree = {{ tree }};
If you're not passing this data to JavaScript, but using it in Jinja instead, you don't need JSON. Pass the actual Python data, don't call tojson on it, and use it as you would any other data in the template.
return render_template('tree.html', tree=tree)
{% for item in tree %}
<li>{{ item }}</li>
{% endfor %}
I could archive it using the following code sample.
<script>
console.log(JSON.parse({{json|safe}}))
</script>
The problem is that your server returns not JSON, but rendered HTML, which escapes some of the symbols with & notation.
Instead of using
return render_template("folder.html", data=tree)
try
return flask.jsonify(**tree)

Issue in storing Mysql Data From Flask to jinja (HTML) variable as json [duplicate]

I am trying to pass data as JSON from a Flask route to a Jinja template rendering JavaScript. I want to iterate over the data using JavaScript. The browser shows SyntaxError: Unexpected token '&'. Expected a property name. when JSON.parse is called on the rendered data. How do I use rendered JSON data in JavaScript?
var obj = JSON.parse({{ data }})
for (i in obj){
document.write(obj[i].text + "<br />");
}
def get_nodes(node):
d = {}
if node == "Root":
d["text"] = node
else:
d["text"] = node.name
getchildren = get_children(node)
if getchildren:
d["nodes"] = [get_nodes(child) for child in getchildren]
return d
tree = get_nodes("Root")
return render_template("folder.html", data=tree)
If I just put {{ data }} in the HTML part, what I see looks correct.
{'text': 'Root', 'nodes': [{'text': u'Prosjekt3'}, {'text': u'Prosjekt4', 'nodes': [{'text': u'mappe8'}]}]}
Flask's Jinja environment automatically escapes data rendered in HTML templates. This is to avoid security issues if the dev tries to render untrusted user input.
Since you are passing a Python object to be treated as JSON, Flask provides the tojson filter which automatically dumps the data to JSON and marks it safe.
return render_template('tree.html', tree=tree)
var tree = {{ tree|tojson }};
When you just look at the data rendered in HTML, it looks correct because the browser displays the escaped symbols as the real symbols (although in this case you're seeing the string representation of a Python dict, not JSON, so there's still some issues like u markers).
Previous versions of Flask didn't mark the dumped data safe, so you might come across examples like {{ tree|tojson|safe }}, which isn't required anymore.
If you're not rendering JSON (or you already dumped the JSON to a string), you can tell Jinja that data is safe to render without escaping by using the safe filter.
# already dumped to json, so tojson would double-encode it
return render_template('tree.html', tree=json.dumps(tree))
var tree = {{ tree|safe }};
You can also wrap the string in Markup before rendering it, it's equivalent to the safe filter.
# already dumped and marked safe
return render_template('tree.html', tree=Markup(json.dumps(tree)))
var tree = {{ tree }};
If you're not passing this data to JavaScript, but using it in Jinja instead, you don't need JSON. Pass the actual Python data, don't call tojson on it, and use it as you would any other data in the template.
return render_template('tree.html', tree=tree)
{% for item in tree %}
<li>{{ item }}</li>
{% endfor %}
I could archive it using the following code sample.
<script>
console.log(JSON.parse({{json|safe}}))
</script>
The problem is that your server returns not JSON, but rendered HTML, which escapes some of the symbols with & notation.
Instead of using
return render_template("folder.html", data=tree)
try
return flask.jsonify(**tree)

How to return JSON data from Flask without ajax

Suppose I want to render a page (not just JSON) using Flask with some specific data that I fetch from the database. For example
display_data.html includes:
<script src='display_data.js'></script>
...
<h1>Data display page!</h1>
<div id="chartContainer"></div>
display_data.js:
$(function() {
draw_chart($("#chartContainer"), json_data);
//draw_chart is defined elsewhere and json_data is what I want to pass in
});
Python:
#app.route('/<data_id>')
def get_display_data_page(data_id):
data = get_data_by_id(data_id)
return render_template('display_data.html', data = data)
I think that if I want to just "render template", I'd have to include elsewhere in display_data.html the following:
<script>window.json_data = {{ data | tojson | safe}}</script>
This pattern smells bad: I'm leaving an object on the global namespace (so that my JS file can access it), displaying the data as plain text, and rendering a string in that is parsed into JSON so the JS can use it. Looks bad but this does work.
Two other options:
Return the data with AJAX. Given the title of this post I'm specifically trying to avoid ajax. The reason for this is mainly that I'm building a mobile site and want to reduce the number of pings back to the server. I'm also thinking (perhaps more metaphysically) about encapsulating the page: once you have it, you have all of it.
Render my JS file via Flask and Jinja. This seems like a bummer because I'd have to then write a route down and render the JS based on the same logic that I have in the get_display_data_page: looking up the data by its id, etc. Code duplication and dynamic JS sound like big no-no's to me.
Is there a known pattern to doing this well?
There's no need to leave data in the global scope if you don't want to. In your template you can do something like this:
<script>
function registerTask(f, args) {
$(function() {
f.call(this, args);
});
}
{% for name, args in js_tasks %}
registerTask({{name}}, {{ args | tojson | safe }});
{% endfor %}
</script>
Then, in your JS file, redefine draw_chart to just take the data (or have a wrapper around it that you use as your task registry name):
function draw_chart_task(data) {
draw_chart($('#chartContainer'), data);
}
Finally, in your controller, simply provide the data and the task name as a tuple:
return render_template('display_data.html', js_tasks=[('draw_chart_task', data)])
This ensures that your JavaScript is not just plucking its dependencies out of the global scope, and you are not making extra network calls.
The data is visible in the raw text output of the page, but it is visible if you make an AJAX call too, you just have to look in a different panel of your browser's developer's tools to see it.

Unescape html entities from JSON in Django templates

I'm getting the response from server that is escaped:
'item':'<b> Some Data </b>'
I pass such data to template useing item= json.loads(response)
By default django templates (in Google App Engine) escapes it further,
so its double escaped in results.
I can use safe to remove one level of escaping like:
{{item|safe}}
How do i turn entities to their corresponding signs?
You can do this:
{% autoescape off %}
{{ your_text_var }}
{% endautoescape %}
Warning - THIS IS NOT A RECOMMENDED SOLUTION. You should be using autoescaping instead (check Rafael's answer).
Following should do the job.
response.replace('&', '&').replace('<', '<').replace('>', '>')
Update -
After suggestion by Jan Schär, you should rather use the following :
response.replace('<', '<').replace('>', '>').replace('&', '&')
Because, if response is &gt;, it would result in > instead of the correct >. You should resolve & in the last.

Categories