Flask url_for URLs in Javascript - javascript

What is the recommended way to create dynamic URLs in Javascript files when using flask? In the jinja2 templates and within the python views url_for is used, what is the recommended way to do this in .js files? Since they are not interpreted by the template engine.
What basically want to do is:
// in comments.js
$.post(url_for('comment.comment_reply'));
Which is not possible.
But naturally, I can execute that in a template:
<script>
$.post(url_for('comment.comment_reply'));
</script>

What #dumbmatter's suggesting is pretty much considered a de facto standard way. But I thought there would be a nicer way of doing it. So I managed to develop this plugin: Flask-JSGlue.
After adding {{ JSGlue.include() }}, you can do the following in your source code:
<script>
$.post(Flask.url_for('comment.comment_reply', {article_id: 3}));
</script>
or:
<script>
location.href = Flask.url_for('index', {});
</script>

The Flask documentation suggests using url_for in your HTML file to set a variable containing the root URL that you can access elsewhere. Then, you would have to manually build the view URLs on top of that, although I guess you could store them similar to the root URL.

Was searching for a solution, them come up with this solution where
No add-on is required
No hard-coding URL
The key is to realise Jinja2 has the ability to render javascript out of the box.
Setup your template folder to something like below:
/template
/html
/index.html
/js
/index.js
In your views.py
#app.route("/index_js")
def index_js():
render_template("/js/index.js")
Now instead of serving the javascript from your static folder. You would use:
<script src="{{ url_for('index_js') }}"></script>
After all, you are generating the javascript on the fly, it is no longer a static file.
Now, inside of you javascript file, simply use the url_for as you would in any html file.
For example using Jquery to make an Ajax request
$.ajax({
url: {{ url_for('endpoint_to_resource') }},
method: "GET",
success: call_back()
})

#jeremy's answer is correct and probably the more common approach, but as an alternative answer, note that dantezhu wrote and published a flask extension that claims to do the exact url-route-map-to-javascript translation suggested in the comment.

I use this dirty and ugly trick:
"{{url_for('mypage', name=metadata.name,scale=93,group=2)}}"
.replace('93/group',scale+'/group')
where scale is the javascript variable I want to use for an AJAX request.
So, url_for generate an URL and JavaScript replace the parameter at runtime. The generated code is something like:
"/ajaxservive/mynam/scale/93/group/2".replace('93/group',scale+'/group')
which is pretty strange, but still can't find more elegant solutions.
In fact, looking at the code of the linked flask extension, it does the same thing but managing the general case.

In my case,
I was trying to dynamically create urls
I solved my issue as follows (Note: I've swapped out Angular's syntax to {[x]}:
<ul>
<li ng-repeat="x in projects">
{[x.title]}
{% set url = url_for('static',filename="img/") %}
<img src="{{url}}{[x.img]}">
</li>
</ul>

I was able to pass a dynamically created url route to a javascript function by using "tojson" with Jinja2 and Flask.
To pass the dynmaic url from the html template to js, simply add '|tojson' at the end of your jinja statment to convert it to the appropriate format.
Instead of:
<script>
$.post(url_for('comment.comment_reply'));
</script>
Try:
<script>
var route = {{ url_for('comment.comment_reply')|tojson }};
yourJavaScriptFunction(route);
</script>
Then you will be able to use the route in your js functions as the correct route for whatever you need.
yourJavaScriptFunction(route){
console.log(route);
}

I was trying to call a FLASK route when a button is pressed. It should collect the response and update a div. The page should not reload.
I used jquery to do this.
Here's the code:
#app.route('/<name>')
def getContent(name):
return 'This is %s' % name
HTML:
<div id="mySpace" class="my-3">Count</div>
<button id="next_id" class="btn btn-primary">Press</button>
<script>
$('#next_id').click(function (){
$.get('/aroy', function(data, status){
$('#mySpace').html(data);
});
});
</script>

I suggest this:
<script src="{{ url_for('static', filename='js/jquery.js') }}" type="text/javascript">
</script>
Works fine for me

Related

Best practice for Javascript which requires context variables in Django

Until now I have been including scripts in my templates by using {% load static %} and having the javascript code in the static directory, separated from html files, because I thought it was the best practice.
But more and more I need to use context variables in the javascript. Since template tags cannot be integrated directly in the individual javascript static files (as far as I know), I have been importing these values in the javascript from the rendered template by using selectors. For example:
<!--template.html-->
<div id="url_ajax" style="display:none">{% url
"images:products" %}</div>
{%load static%}
<script src="{% static "js/ajax.js" %}"></script>
/*Ajax.js*/
url_ajax = document.getElementById("url_ajax").innerHTML
$.post(url_ajax, {
rankit: this.rankit,
pd: JSON.stringify(pd)
},
function(data) {
if (data['status'] == 'ok') {
[...]
}
}
);
Although this works, I am feeling this is not a good practice due to security reasons or scalability. But I do not know another way of integrating context variables in the javascript rather than integrating javascript code directly in the template, which is neither a good approach if that code will be used in many templates.
As a Django learner I would like to know which is the most often used approach in these situations: separated javascript files which takes context variables from the rendered template, javascript code inserted directly in the template html, or a third approach which I donĀ“t know?
I don't really like your solution, there's no need to create an extra html element to pass the django variable and read it from JS. This is error prone and adds non-needed html elements to your DOM.
Instead I recommend two solutions:
Solution 1
Use a JS script in your template where you'll dump your JS variables and then use them directly from your JS files. To do that, I'll usually have a script inside my template before my custom JS code where I define a global JS object containing all Django variables, like this:
<script>
var g_django = {
url1: '{% url "the_first_url" %}',
url2: '{% url "the_second_url" %}',
image: '{% static "images/an_image" %}'
}
</script>
<script src='{% static "js/ajax.js" %}'></script>
Now I can use g_django.url1, g_django.image etc from inside the js/ajax.js script. This can be used if you don't have many things you need to share between django and JS.
Solution 2
If you have more things you need to share between Django and js and you want to have better control you can create a JS-Django template i.e create a normal JS file inside your templates folder. This file can then either be included inside a <script> tag (check my answer here for a similar solution with css: Django Use Static files URL in Static Files) or, even better be used as a normal django view through a TemplateView. Thus, you'll create a file named django_data.js in your templates folder in which you'll write JS code mixed with django variables for example it's contents may be something like this
var g_django = {
url1: '{% url "the_first_url" %}',
url2: '{% url "the_second_url" %}',
image: '{% static "images/an_image" %}'
}
This file will then need to be included to your urls.py through a TemplateView something like this:
class django.views.generic.base.TemplateView
urlpatterns = [
path('django_data_js/', TemplateView.as_view(template='django_data.js', content_type='application/javascript'), name='django_data_js' ),
]
Now you can visit django_data_js/ to take a look at your JS variables and be sure that everything renders correctly and of course you can include it (as a template) to your scripts like this:
<script src='{% url "django_data_js" %}'></script>
<script src='{% static "js/ajax.js" %}'></script>
Notice the difference between including the template-js (using url) and including the normal static file (using static). You'll then be able to use g_django from inside your js/ajax.js.

Passing parameter(s) to Javascript file from Python Flask app through HTML

I am building a Python/Flask based web app. The python script produces a dictionary of words and their corresponding weights. I have a javascript file (let's call it custom.js), which I call from the output.html. The way this javascript works is that it takes this dictionary and then uses d3.v3.min.js and d3.layout.cloud.js to create a wordcloud. When the dictionary is hard-coded into custom.js, the output file shows the wordcloud. However, the dictionary values will change depending on other parameters in the python script. Therefore, I would like to pass this dictionary from Python to custom.js. I am not sure how to do that.
I know that the parameters could be passed to HTML using {{ params |safe }}, but I am trying to figure out how to do that so that custom.js will receive the parameters (dictionary of words and weights, in this case) and word clouds can be rendered dynamically.
Thank you in advance!
If I understood you correctly you need to create a view function (a route) in the flask backend with url like this /get_dictionary. This function can look like this:
from flask import request, jsonify
...
#app.route('/get_dictionary'):
def get_dictionary():
...
your_dictionary = []
# Fill in your_dictionary with data
...
render_template('your_template.html', your_dictionary=your_dictionary)
EDIT:
You can pass the data from flask to script section of the html template using standard jinja2 notation:
<html>
<head>
<script>
your_dictionary = {{ your_dictionary | tojson }}
<!-- Do what you need with your_dictionary -->
</script>
...
</head>
...
you can try define a var in your template html, like this:
<script>
var your_var = '{{ value }}'
</script>
then use "your_var" in external js file. But please make sure above definition is at ahead of your js file refer.

Unable to pass jinja2 variables into javascript snippet

How do i pass jinja2 data into javascript.
I have a Flask REST url as /logs/<test_case_name>
I am trying use .getJSON() to query the above URL and hence would want to pass the jinja2 data which has the testcasename to .getJSON function.
sample code:
<script type="text/javascript">
alert({{name}});
</script>
It doesn't work.
Any suggestions please?
Try with quotes:
alert("{{name}}");
other than encapsulating the variable in a string, an alternate is jquery for profit:
its generally a bad idea to mix template language with javascript. An alternative would be to use html as a proxy - store the name in an element like so
<meta id="my-data" data-name="{{name}}" data-other="{{other}}">
then in the javascript do
var djangoData = $('#my-data').data();
this has advantage in:
javascript no longer tied to the .html page
jquery coerces data implicitly
I know this is a kinda old topic, but since it attracts a lot of views I suppose some people are still looking for an answer.
Here's the simplest way to do it:
var name = {{name|tojson}};
It will 'parse' whatever 'name' is and display it correctly:
https://sopython.com/canon/93/render-string-in-jinja-to-javascript-variable/
This is how I did it
My html Element
<!--Proxy Tag for playlist data-->
<meta id="my_playlist_data" data-playlist="{{ playlist }}">
My script element
// use Jquery to get data from proxy Html element
var playlist_data = $('#my_playlist_data').data("playlist");
See .data() documenttation for more
I just figure I would add the solution I ended up using.
It has a few advantages over the other answers:
It is 100% valid javascript at the template level (no editor/lint errors).
Does not need any special HTML tag.
No dependencies (jquery, or otherwise).
let data = JSON.parse('{{ data | tojson }}');
you can try alert({{name|safe}});
<input type="hidden" name="token_idx" id="token_idx" value='{{token|safe }}'
let token_data = document.getElementById("token_idx").value;

How to pass a parameter by URL to the JavaScript code on GAE?

I'd like to pass a parameter in request URL to the JavaScript code on GAE environment.
For example, following URL was entered.
http://example.com:8080/hello?key=abc
The hello page was rendered with hello.py and hello.tmpl which are shown below respectively.
'''hello.py'''
key = self.request.get('key')
{# hello.tmpl #}
<html>
<div id="key">{{ key }}</div>
<script src="hello.js"></script>
</html>
In order to refer the key specified with URL in hello.js, the function can be written as following.
// hello.js
function() {
console.log($('#key').text());
};
It works well and meets my original request that a parameter was propagated from the URL to the JavaScript Code.
However, I felt like it's not a smart way. I used div tag as a buffer between URL and JavaScript code. Does anyone know any smarter way to do this?
You can use data extension instead of adding a div:
<body data-key='{{key}}'>
<...>
</body>
// hello.js
function() {
console.log($('body').data('key'));
};

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