How to set a jinja2 expression with a Javascript variable? - javascript

How can I use a Jinja2 expression within a js function? I'd tried something similar to the lines below and the expression isn't working. The attribute fileList used in response is a list coming from flask through Json.
var response = JSON.parse(req.responseText);
{% set myFiles = response.fileList %}

Jinja2 is a templating language. Meaning all template expressions will be evaluated and replaced by either text or HTML code before even served to the client.
Whereas Javascript is a scripting language used on the client side.
So there is actually no way to pass any values to a Jinja2 expression from Javascript as there simply don't exist any Jinja2 expressions on the client side because they have all been replaced already by text or html code.
However if you simply want to pass any data from client to server there are a lot of ways to do that. Probably the most fitting for you would be an Ajax call.

I think you looking for including expression or statement in js.
It's possible, use double quotes(" "). One thing you can't directly add in the js file. use your code at the end of the code
var response = JSON.parse(req.responseText);
"{% set myFiles = response.fileList %}"
For Clear Understanding,
app.py
#app.route('/')
def home():
return render_template('index.html',check=0,text='hai')
index.html
<div>
.
.
.
</div>
<script>
var text = {{ text }} //Throws error
var text = "{{ text }}" //console it
{% if(check == 0) %}
console.log('its true')
{% endif %} //Throw error
"{% if(check == 0) %}"
console.log('its true')
"{% endif %}"//Success
</script>
It's working for me. vote if works

Related

How to use javascript variable in django if statement (template)?

I'm trying to update my html element with django if statement:
element.innerHTML= `{% if person.name == ${value} %} something {% endif %}`
but I receive an error:
TemplateSyntaxError at /
Could not parse the remainder: '${value}' from '${value}'
I also tried:
`{% if person.name == ${value} %} something {% endif %}`
But the statement doesn't work properly.
Is there anything I can do to combine javascript with Django variables?
Short Answer
No. You can not do this, at least not that easily.
Detailed (slightly) Answer
Django replaces all tags, {{ }} and {% %} with the result at the server (back end) end when the page is rendered, before it gets to the client. Your JavaScript (JQuery?) variable is evaluated by the client (the front end). Django will not know what ${value} is. So, no, you can not use a JavaScript variable in Django template code.
This does not mean you can not achieve what you want, but it must be done in the following way. Your JavaScript code can fetch the value of person.name from a view and then you can do your if statement in the JavaScript file after the response from the fetch is received. The view could return the value of person.name as a JsonResponse

Sending JSON data as context quotes becoming "?

I am trying to send some schedule data to a webpage using Django and JSON format. My view to send this data looks like this:
def sessionscheduler(request):
c = connection.cursor()
c.execute("SELECT * FROM meter_schedule WHERE id = 1")
scheduleArray = []
for row in c.fetchall():
data = dict([('lastUpdate',row[1]), ('weekdaysOn',row[2]), ('weekdayChargeRateOffPeriodKwh',row[3]), ('weekdayEveningChargeOn',row[4]), ('weekdayEveningStart',row[5]),
('weekdayEveningDuration',row[6]), ('weekdayDayChargeOn',row[7]), ('weekdayDayStart',row[8]), ('weekdayDayDuration',row[9]), ('weekendsOn',row[10]),
('weekendChargeRateOffPeriodKWh',row[11]), ('weekendEveningChargeOn',row[12]), ('weekendEveningStart',row[13]), ('weekendEveningDuration',row[14]),
('weekendDayChargeOn',row[15]), ('weekendDayStart',row[16]), ('weekendDayDuration',row[17])])
scheduleArray.append(data)
jscheduleArray = json.dumps(scheduleArray)
context = {'jscheduleArray' : jscheduleArray}
return render(request, 'sessionscheduler.html', context)
I have used a template to render what is in jscheduleArray and it is coming out exactly how I want on the HTML page. However I want to use this data in my JavaSript file. The problem is that the quotes are not "" in the page source they are " which the script does not like. How do I fix this. Also I have a separte js file, is there anyway to directly call the JSON object into the the .js file? I am using YUI and pure JS.
I think you can use autoescape tag in your template to not escape the quotes
# sessionscheduler.html
{% autoescape off %}
{{ your_string }}
{% endautoescape %}

Django reverse url in javascript

This javascript
window.location.href = "{% url 'namespace:name' object.slug " + currentRow + " %}"
results in a NoReverseMatch error because it takes "currentRow" as a parameter instead of the value behind currentRow.
You are mixing Javascript and the Django template engine.
The Django template engine sees no Javascript variables. No script tags. It only sees text.
Javascript is processed on the clientside, after your HTML and Javascript is generated on the server side by the Django template engine.
If you have a context variable (e.g. coming from your Django view or maybe created in a {% for %} loop) named currentRow, you can use it directly like so:
window.location.href = "{% url 'namespace:name' object.slug currentRow %}"

How to pass a list from Python, by Jinja2 to JavaScript

Let's say I have a Python variable:
list_of_items = ['1','2','3','4','5']
and I pass it to Jinja by rendering HTML, and I also have a function in JavaScript called somefunction(variable). I am trying to pass each item of list_of_items. I tried something like this:
{% for item in list_of_items %}
<span onclick="somefunction({{item}})">{{item}}</span><br>
{% endfor %}
Is it possible to pass a list from Python to JavaScript or should I pass each item from list one by one in a loop? How can I do this?
To pass some context data to javascript code, you have to serialize it in a way it will be "understood" by javascript (namely JSON). You also need to mark it as safe using the safe Jinja filter, to prevent your data from being htmlescaped.
You can achieve this by doing something like that:
The view
import json
#app.route('/')
def my_view():
data = [1, 'foo']
return render_template('index.html', data=json.dumps(data))
The template
<script type="text/javascript">
function test_func(data) {
console.log(data);
}
test_func({{ data|safe }})
</script>
Edit - exact answer
So, to achieve exactly what you want (loop over a list of items, and pass them to a javascript function), you'd need to serialize every item in your list separately. Your code would then look like this:
The view
import json
#app.route('/')
def my_view():
data = [1, "foo"]
return render_template('index.html', data=map(json.dumps, data))
The template
{% for item in data %}
<span onclick=someFunction({{ item|safe }});>{{ item }}</span>
{% endfor %}
Edit 2
In my example, I use Flask, I don't know what framework you're using, but you got the idea, you just have to make it fit the framework you use.
Edit 3 (Security warning)
NEVER EVER DO THIS WITH USER-SUPPLIED DATA, ONLY DO THIS WITH TRUSTED DATA!
Otherwise, you would expose your application to XSS vulnerabilities!
I had a similar problem using Flask, but I did not have to resort to JSON. I just passed a list letters = ['a','b','c'] with render_template('show_entries.html', letters=letters), and set
var letters = {{ letters|safe }}
in my javascript code. Jinja2 replaced {{ letters }} with ['a','b','c'], which javascript interpreted as an array of strings.
You can do this with Jinja's tojson filter, which
Dumps a structure to JSON so that it’s safe to use in <script> tags [and] in any place in HTML with the notable exception of double quoted attributes.
For example, in your Python, write:
some_template.render(list_of_items=list_of_items)
... or, in the context of a Flask endpoint:
return render_template('your_template.html', list_of_items=list_of_items)
Then in your template, write this:
{% for item in list_of_items %}
<span onclick='somefunction({{item | tojson}})'>{{item}}</span><br>
{% endfor %}
(Note that the onclick attribute is single-quoted. This is necessary since |tojson escapes ' characters but not " characters in its output, meaning that it can be safely used in single-quoted HTML attributes but not double-quoted ones.)
Or, to use list_of_items in an inline script instead of an HTML attribute, write this:
<script>
const jsArrayOfItems = {{list_of_items | tojson}};
// ... do something with jsArrayOfItems in JavaScript ...
</script>
DON'T use json.dumps to JSON-encode variables in your Python code and pass the resulting JSON text to your template. This will produce incorrect output for some string values, and will expose you to XSS if you're trying to encode user-provided values. This is because Python's built-in json.dumps doesn't escape characters like < and > (which need escaping to safely template values into inline <script>s, as noted at https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements) or single quotes (which need escaping to safely template values into single-quoted HTML attributes).
If you're using Flask, note that Flask injects a custom tojson filter instead of using Jinja's version. However, everything written above still applies. The two versions behave almost identically; Flask's just allows for some app-specific configuration that isn't available in Jinja's version.
To add up on the selected answer, I have been testing a new option that is working too using jinja2 and flask:
#app.route('/')
def my_view():
data = [1, 2, 3, 4, 5]
return render_template('index.html', data=data)
The template:
<script>
console.log( {{ data | tojson }} )
</script>
the output of the rendered template:
<script>
console.log( [1, 2, 3, 4] )
</script>
The safe could be added but as well like {{ data | tojson | safe }} to avoid html escape but it is working without too.
I can suggest you a javascript oriented approach which makes it easy to work with javascript files in your project.
Create a javascript section in your jinja template file and place all variables you want to use in your javascript files in a window object:
Start.html
...
{% block scripts %}
<script type="text/javascript">
window.appConfig = {
debug: {% if env == 'development' %}true{% else %}false{% endif %},
facebook_app_id: {{ facebook_app_id }},
accountkit_api_version: '{{ accountkit_api_version }}',
csrf_token: '{{ csrf_token }}'
}
</script>
<script type="text/javascript" src="{{ url_for('static', filename='app.js') }}"></script>
{% endblock %}
Jinja will replace values and our appConfig object will be reachable from our other script files:
App.js
var AccountKit_OnInteractive = function(){
AccountKit.init({
appId: appConfig.facebook_app_id,
debug: appConfig.debug,
state: appConfig.csrf_token,
version: appConfig.accountkit_api_version
})
}
I have seperated javascript code from html documents with this way which is easier to manage and seo friendly.
you can do it
<tbody>
{% for proxy in proxys %}
<tr>
<td id={{proxy.ip}}>{{proxy.ip}}</td>
<td id={{proxy.port}}>{{proxy.port}}</td>
<td>{{proxy.protocol}}</td>
<td>{{proxy.speed}}</td>
<td>{{proxy.type}}</td>
<td>{{proxy.city}}</td>
<td>{{proxy.verify_time}}</td>
<td>
<button type="button" class="btn btn-default" aria-label="Left Align">
<span class="glyphicon glyphicon-paste" aria-hidden="true" onclick="copyProxy('{{proxy.ip}}', '{{proxy.port}}')"></span>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
Make some invisible HTML tags like <label>, <p>, <input> etc. and name its id, and the class name is a pattern so that you can retrieve it later.
Let you have two lists maintenance_next[] and maintenance_block_time[] of the same length, and you want to pass these two list's data to javascript using the flask. So you take some invisible label tag and set its tag name is a pattern of list's index and set its class name as value at index.
{% for i in range(maintenance_next|length): %}
<label id="maintenance_next_{{i}}" name="{{maintenance_next[i]}}" style="display: none;"></label>
<label id="maintenance_block_time_{{i}}" name="{{maintenance_block_time[i]}}" style="display: none;"></label>
{% endfor%}
Now you can retrieve the data in javascript using some javascript operation like below -
<script>
var total_len = {{ total_len }};
for (var i = 0; i < total_len; i++) {
var tm1 = document.getElementById("maintenance_next_" + i).getAttribute("name");
var tm2 = document.getElementById("maintenance_block_time_" + i).getAttribute("name");
//Do what you need to do with tm1 and tm2.
console.log(tm1);
console.log(tm2);
}
</script>

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