Flask with Jinja2 - Passing value from Flask to Javascript using Jinja2 statements - javascript

This is my code in Flask
data = {"Bird" : "Its a bird!"}
#app.route('/store')
def store():
return render_template('store.html', data = data)
This is my code in Javascript
<script>
var val = "Bird";
var something = '{{ data[' + val +'] }}';
</script>
I'm not sure what i'm doing wrong but I cant seem to get something to be "Its a bird!".
Any ideas?

You have to keep in mind that Jinja2 template rendering happens before the JavaScript is executed. You can see this in the fact that you render the template and then return it to the user (or their browser).
Therefore, anything that comes out of that template render process, must be valid JavaScript in order to run. Also, Jinja2 does not know anything about HTML, JavaScript or really any other language.
Putting this knowledge into use would basically mean that you need to render the required data into valid JavaScript:
<script>
var mapping = {{ data | tojson }};
var val = "Bird";
var something = mapping[val];
</script>
Personally, however, I would avoid templating JavaScript code and figure out some other way or handling dynamic data.

Related

How to pass a Javascript variable in django template-tag

Hello i have this question
if have a variable
<script>
var a = True
<script>
can i use the variable like
{% if a %}
<h1> True</h1>
{%else%}
<h1> False </h1>
{%endif%}
The both pieces of code are in the same page
I don't want to use filters it will complicate a lot my work Thank you
You can do the html modification in JavaScript
Ex:
<script>
var a = true;
if (a){
document.getElementById("your_h2_tag_ID").innerHTML = "True";
}else{
document.getElementById("your_h2_tag_ID").innerHTML = "False";
}
<script>
No, you can't. For Django, var a = True is just a string.
Django is the one that creates the HTML and tells the browser what strings to use, and the browser will interpret the string and find it to be JavaScript, so it'll execute and finally see that a is a boolean.
By the time it does that, Django is long gone
The only way you can tell django to use a as a boolean, is to make another request to the server, sending a as a JSON or querystring parameter, and later interpret the request from python/django and use it in templates. (quite a costly task)

Issue with fetching data from python handler to javascript using jinja2 and google app engine

I am working on a python based Google App Engine project.
And in that I was trying to send data(python list) from python handler to javascript using jinja2 but cannot receive data in javascript.
I even tried to send simple key-value instead of list and json but that too didn't worked.
Here is my code for python handler :
mainDataList=[]
keyList = ['key1','key2','key3']
valueList = ['value1', 'value2', 'value3']
mainDataList.append(keyList)
mainDataList.append(valueList)
template_values={
'keyList':mainDataList[0],
'valueList':mainDataList[1],
}
template = jinja_environment.get_template('main.html')
self.response.out.write(template.render(template_values))
Code inside head tag
<script type="text/javascript">
var keyListToPopulate = {{ keyList | safe }};
var valueListToPopulate = {{ valueList | safe }};
</script>
Can you please help me with the error I am making.
Putting data into inline javascript like that is just string processing. You need to put the right string into your template variables. json.dumps() produces the string that you need. Something like this should work:
template = jinja_environment.get_template('main.html')
self.response.out.write(template.render({"keyList":json.dumps(range(5)),
"valueList":json.dumps(["A", "B"])}
))

Convert ejs snippet to jade

I have some server-side ejs templates I'm converting to jade for my node.js/express app, but there's one piece of ejs code that I"m a bit unsure of how to properly write in jade. Here's the snippet.
<script type="text/javascript">
window.user = <%- user || 'null' %>;
</script>
I tried doing something like this in jade, but it's obviously wrong since user is returned as undefined.
script.
window.user = user || 'null';
I also tried using a ternary operation, which does't give an error but also doesn't return a user.
script.
window.user ? user : 'null';
I basically have a user object the server controller is passing to the server template. What's the proper way to handle passing objects from the controller to the view? I'm a bit of a back end development noob so I apologize if this is a silly question.
This works, if user is falsy (null, undefined, empty string etc.):
script(type='text/javascript').
window.user = "#{user}" || null;
If you are certain not to escape the users value, which means you may be vulnerable to CSS-attacks, you may use !{user} instead of #{user}.
I have bean trying the snippet here: http://jade-lang.com/demo/

Safely Using JSON with html inside of the JSON in Django Templates

How do you safely render JSON data in a django webapp?
On the server in django I generate JSON data and then render that JSON data in a django template. The JSON occasionally contains snippets of html. Most of the time, that's fine, however if the </script> tag is inside the JSON data when it is rendered, it destroys the surrounding javascript.
For example...
On the server, in python I'll have this:
template_data = {
'my_json' : '[{"my_snippet": "<b>Happy HTML</b>"}]'
}
# pass the template data to the django template
return render_to_response('my_template.html', template_data, context_instance = c)
And then in the template:
<script type="text/javascript">
var the_json = {{my_json|safe}};
</script>
... some html ...
The resulting html works fine and looks like this:
<script type="text/javascript">
var the_json = [{"my_snippet": "<b>Happy HTML</b>"}];
</script>
... some html ...
However, you run into problems when, on the server, the JSON looks like this:
template_data = {
'my_json' : '[{"my_snippet": "Bad HTML</script>"}]'
}
return render_to_response('my_template.html', template_data, context_instance = c)
Now, when it's rendered, you'll get:
<script type="text/javascript">
var the_json = [{"my_snippet": "Bad HTML</script>"}];
</script>
... some html ...
The closing script tag within the JSON code is treated as closing the entire script block. All of your javascript will then break.
One possible solution is to check for </script> when passing the template data to the template, but I feel like there is a better way.
Safely insert the JSON as a string, and then call JSON.parse on it
Use escapejs instead of safe. It is designed for outputting to JavaScript.
var the_json = '{{my_json|escapejs}}';
To get a JavaScript object you then need to call JSON.parse on that string. This is always preferable than dumping a JSON-encoding into your script and evaluating it directly, for security reasons.
A useful filter to get python objects directly to the client that I use is this:
#register.filter
def to_js(value):
"""
To use a python variable in JS, we call json.dumps to serialize as JSON server-side and reconstruct using
JSON.parse. The serialized string must be escaped appropriately before dumping into the client-side code.
"""
# separators is passed to remove whitespace in output
return mark_safe('JSON.parse("%s")' % escapejs(json.dumps(value, separators=(',', ':'))))
And use it like:
var Settings = {{ js_settings|to_js }};

Django Template Variables and Javascript

When I render a page using the Django template renderer, I can pass in a dictionary variable containing various values to manipulate them in the page using {{ myVar }}.
Is there a way to access the same variable in Javascript (perhaps using the DOM, I don't know how Django makes the variables accessible)? I want to be able to lookup details using an AJAX lookup based on the values contained in the variables passed in.
The {{variable}} is substituted directly into the HTML. Do a view source; it isn't a "variable" or anything like it. It's just rendered text.
Having said that, you can put this kind of substitution into your JavaScript.
<script type="text/javascript">
var a = "{{someDjangoVariable}}";
</script>
This gives you "dynamic" javascript.
CAUTION Check ticket #17419 for discussion on adding similar tag into Django core and possible XSS vulnerabilities introduced by using this template tag with user generated data. Comment from amacneil discusses most of the concerns raised in the ticket.
I think the most flexible and handy way of doing this is to define a template filter for variables you want to use in JS code. This allows you to ensure, that your data is properly escaped and you can use it with complex data structures, such as dict and list. That's why I write this answer despite there is an accepted answer with a lot of upvotes.
Here is an example of template filter:
// myapp/templatetags/js.py
from django.utils.safestring import mark_safe
from django.template import Library
import json
register = Library()
#register.filter(is_safe=True)
def js(obj):
return mark_safe(json.dumps(obj))
This template filters converts variable to JSON string. You can use it like so:
// myapp/templates/example.html
{% load js %}
<script type="text/javascript">
var someVar = {{ some_var | js }};
</script>
A solution that worked for me is using the hidden input field in the template
<input type="hidden" id="myVar" name="variable" value="{{ variable }}">
Then getting the value in javascript this way,
var myVar = document.getElementById("myVar").value;
As of Django 2.1, a new built in template tag has been introduced specifically for this use case: json_script.
https://docs.djangoproject.com/en/stable/ref/templates/builtins/#json-script
The new tag will safely serialize template values and protects against XSS.
Django docs excerpt:
Safely outputs a Python object as JSON, wrapped in a tag,
ready for use with JavaScript.
There is a nice easy way implemented from Django 2.1+ using a built in template tag json_script. A quick example would be:
Declare your variable in your template:
{{ variable|json_script:'name' }}
And then call the variable in your <script> Javascript:
var js_variable = JSON.parse(document.getElementById('name').textContent);
It is possible that for more complex variables like 'User' you may get an error like "Object of type User is not JSON serializable" using Django's built in serializer. In this case you could make use of the Django Rest Framework to allow for more complex variables.
new docs says use {{ mydata|json_script:"mydata" }} to prevent code injection.
a good exmple is given here:
{{ mydata|json_script:"mydata" }}
<script>
const mydata = JSON.parse(document.getElementById('mydata').textContent);
</script>
For a JavaScript object stored in a Django field as text, which needs to again become a JavaScript object dynamically inserted into on-page script, you need to use both escapejs and JSON.parse():
var CropOpts = JSON.parse("{{ profile.last_crop_coords|escapejs }}");
Django's escapejs handles the quoting properly, and JSON.parse() converts the string back into a JS object.
Here is what I'm doing very easily:
I modified my base.html file for my template and put that at the bottom:
{% if DJdata %}
<script type="text/javascript">
(function () {window.DJdata = {{DJdata|safe}};})();
</script>
{% endif %}
then when I want to use a variable in the javascript files, I create a DJdata dictionary and I add it to the context by a json : context['DJdata'] = json.dumps(DJdata)
Hope it helps!
For a dictionary, you're best of encoding to JSON first. You can use simplejson.dumps() or if you want to convert from a data model in App Engine, you could use encode() from the GQLEncoder library.
Note, that if you want to pass a variable to an external .js script then you need to precede your script tag with another script tag that declares a global variable.
<script type="text/javascript">
var myVar = "{{ myVar }}"
</script>
<script type="text/javascript" src="{% static "scripts/my_script.js" %}"></script>
data is defined in the view as usual in the get_context_data
def get_context_data(self, *args, **kwargs):
context['myVar'] = True
return context
I was facing simillar issue and answer suggested by S.Lott worked for me.
<script type="text/javascript">
var a = "{{someDjangoVariable}}"
</script>
However I would like to point out major implementation limitation here.
If you are planning to put your javascript code in different file and include that file in your template. This won't work.
This works only when you main template and javascript code is in same file.
Probably django team can address this limitation.
I've been struggling with this too. On the surface it seems that the above solutions should work. However, the django architecture requires that each html file has its own rendered variables (that is, {{contact}} is rendered to contact.html, while {{posts}} goes to e.g. index.html and so on). On the other hand, <script> tags appear after the {%endblock%} in base.html from which contact.html and index.html inherit. This basically means that any solution including
<script type="text/javascript">
var myVar = "{{ myVar }}"
</script>
is bound to fail, because the variable and the script cannot co-exist in the same file.
The simple solution I eventually came up with, and worked for me, was to simply wrap the variable with a tag with id and later refer to it in the js file, like so:
// index.html
<div id="myvar">{{ myVar }}</div>
and then:
// somecode.js
var someVar = document.getElementById("myvar").innerHTML;
and just include <script src="static/js/somecode.js"></script> in base.html as usual.
Of course this is only about getting the content. Regarding security, just follow the other answers.
I have found we can pass Django variables to javascript functions like this:-
<button type="button" onclick="myJavascriptFunction('{{ my_django_variable }}')"></button>
<script>
myJavascriptFunction(djangoVariable){
alert(djangoVariable);
}
</script>
I use this way in Django 2.1 and work for me and this way is secure (reference):
Django side:
def age(request):
mydata = {'age':12}
return render(request, 'test.html', context={"mydata_json": json.dumps(mydata)})
Html side:
<script type='text/javascript'>
const mydata = {{ mydata_json|safe }};
console.log(mydata)
</script>
you can assemble the entire script where your array variable is declared in a string, as follows,
views.py
aaa = [41, 56, 25, 48, 72, 34, 12]
prueba = "<script>var data2 =["
for a in aaa:
aa = str(a)
prueba = prueba + "'" + aa + "',"
prueba = prueba + "];</script>"
that will generate a string as follows
prueba = "<script>var data2 =['41','56','25','48','72','34','12'];</script>"
after having this string, you must send it to the template
views.py
return render(request, 'example.html', {"prueba": prueba})
in the template you receive it and interpret it in a literary way as htm code, just before the javascript code where you need it, for example
template
{{ prueba|safe }}
and below that is the rest of your code, keep in mind that the variable to use in the example is data2
<script>
console.log(data2);
</script>
that way you will keep the type of data, which in this case is an arrangement
There are two things that worked for me inside Javascript:
'{{context_variable|escapejs }}'
and other:
In views.py
from json import dumps as jdumps
def func(request):
context={'message': jdumps('hello there')}
return render(request,'index.html',context)
and in the html:
{{ message|safe }}
There are various answers pointing to json_script. Contrary to what one might think, that's not a one size fits all solution.
For example, when we want to pass to JavaScript dynamic variables generated inside a for loop, it's best to use something like data-attributes.
See it in more detail here.
If you want to send variable directly to a function by passing it as a parameter then try this
<input type="text" onkeyup="somefunction('{{ YOUR_VARIABLE }}')">
As from previous answers the security can be improved upon

Categories

Resources