Django's template tag inside javascript
Question:
My app’s urls.py is:
from django.urls import path
from . import views
app_name = 'javascript'
urlpatterns = [
path('create_table', views.create_table, name='create_table')
My views.py is:
def create_table(request):
row_data = "this is row data"
context = {'row_data': row_data}
return render(request, 'javascript/create_table.html', context)
My create_table.html is:
{% load static %}
<button id="create_table">Get data</button>
<div id="place_for_table"></div></div>
<script src="{% static 'javascript/scripts/create_table.js' %}"></script>
And my create_table.js is:
function create_table() {
document.getElementById("place_for_table").innerHTML = '{{ row_data }}';
}
document.getElementById("create_table").onclick = function() {
create_table()
}
What I am trying to do is to run the create_table.js script on the click of the create_table
button which should display “this is row data” text in place for table
div element.
However, what gets diplayed is just {{ row_data ))
.
I have read other similar questions on using Django’s variables inside Javascript but as per my understanding they all suggest to do the way I did it, so I am not sure what I am doing wrong.
Answers:
When you write {{ row_data }}
, you’re using a Django-specific “language” called Django template language which means that the mentioned syntax can only be “understood” by Django templates.
What you’re doing here is loading a separate JavaScript file in which the Django template syntax simply won’t work because when browser comes to the point to evaluate that file, {{ row_data }}
will look just another string literal, and not what you would expect to.
It should work if you inline your JavaScript example directly into the Django template.
Alternatively you could somehow “bootstrap” the external JavaScript file with the data available in the Django template, here’s how I would go about doing that:
create_table.html
<script src="{% static 'javascript/scripts/create_table.js' %}"></script>
<script type="text/javascript">
$(function() {
var create_table = Object.create(create_table_module);
create_table.init({
row_data: '{{ row_data }}',
...
});
});
</script>
Note: wrapping the above code in the jQuery’s .ready() function is optional, but if you’re already using jQuery in your app, it’s a simple way to make sure the DOM is safe to manipulate after the initial page load.
create_table.js
var create_table_module = (function($) {
var Module = {
init: function(opts) {
// you have access to the object passed
// to the `init` function from Django template
console.log(opts.row_data)
},
};
return Module;
})(jQuery);
Note: passing jQuery instance to the module is optional, it’s just here as an example to show how you can pass an external dependancy to the module.
If you’ve got an element in your template which you’re getting to then detect clicks, why not just do it the other way around where you can then pass the context variable to your JS function?
<button onclick="create_table({{ row_data }})">Click me</button>
By doing that you can inspect the page to see if the data is going to be passed correctly. You’ll probably have to pass the data through a filter like escapejs
or safe
.
Alternatively you could do something like
{% load static %}
<button id="create_table">Get data</button>
<div id="place_for_table"></div></div>
<script type="text/javascript">
var row_data = "{{ row_data }}";
</script>
<script src="{% static 'javascript/scripts/create_table.js' %}">
</script>
The issue with this approach is the scope of variables as you may not want to declare things globally so it could be considered an easy approach, but not necessarily the best solution.
What I did was to include the javascript/jquery inside
{% block scripts %}
and use the the Django specific data as follows:
`
$.ajax({
type:"GET",
url: "/reserve/run/?ip={{ row_data }}",
dataType: "html",
async: true,
}).done(function(response) {
$("#Progress").hide();
$('#clickid').attr('href','javascript:ClearFlag()');
var win = window.open("", "MsgWindow");
win.document.write(response);
});
`
I’ve found a solution to avoid the extra typing of all the previous answers.
It’s a bit hacky:
Just transform you myjavascriptfile.js
into myjavascriptfile.js.html
and wrap the code in a <script>...</script>
tag. Than include
them instead of linking them in your template file.
myTemplate.html
....
{% block js_footer %}
{% include "my_app/myjavascriptfile.js.html" %}
{% endblock js_footer %}
myjavascriptfile.js.html
<script type="text/javascript">
console.log('the time now is {% now "Y m d H:i:s" %}');
...
</script>
instead of writing the function in a separated js file, write it in script tags within your html page, so it can use the django template language
My app’s urls.py is:
from django.urls import path
from . import views
app_name = 'javascript'
urlpatterns = [
path('create_table', views.create_table, name='create_table')
My views.py is:
def create_table(request):
row_data = "this is row data"
context = {'row_data': row_data}
return render(request, 'javascript/create_table.html', context)
My create_table.html is:
{% load static %}
<button id="create_table">Get data</button>
<div id="place_for_table"></div></div>
<script src="{% static 'javascript/scripts/create_table.js' %}"></script>
And my create_table.js is:
function create_table() {
document.getElementById("place_for_table").innerHTML = '{{ row_data }}';
}
document.getElementById("create_table").onclick = function() {
create_table()
}
What I am trying to do is to run the create_table.js script on the click of the create_table
button which should display “this is row data” text in place for table
div element.
However, what gets diplayed is just {{ row_data ))
.
I have read other similar questions on using Django’s variables inside Javascript but as per my understanding they all suggest to do the way I did it, so I am not sure what I am doing wrong.
When you write {{ row_data }}
, you’re using a Django-specific “language” called Django template language which means that the mentioned syntax can only be “understood” by Django templates.
What you’re doing here is loading a separate JavaScript file in which the Django template syntax simply won’t work because when browser comes to the point to evaluate that file, {{ row_data }}
will look just another string literal, and not what you would expect to.
It should work if you inline your JavaScript example directly into the Django template.
Alternatively you could somehow “bootstrap” the external JavaScript file with the data available in the Django template, here’s how I would go about doing that:
create_table.html
<script src="{% static 'javascript/scripts/create_table.js' %}"></script>
<script type="text/javascript">
$(function() {
var create_table = Object.create(create_table_module);
create_table.init({
row_data: '{{ row_data }}',
...
});
});
</script>
Note: wrapping the above code in the jQuery’s .ready() function is optional, but if you’re already using jQuery in your app, it’s a simple way to make sure the DOM is safe to manipulate after the initial page load.
create_table.js
var create_table_module = (function($) {
var Module = {
init: function(opts) {
// you have access to the object passed
// to the `init` function from Django template
console.log(opts.row_data)
},
};
return Module;
})(jQuery);
Note: passing jQuery instance to the module is optional, it’s just here as an example to show how you can pass an external dependancy to the module.
If you’ve got an element in your template which you’re getting to then detect clicks, why not just do it the other way around where you can then pass the context variable to your JS function?
<button onclick="create_table({{ row_data }})">Click me</button>
By doing that you can inspect the page to see if the data is going to be passed correctly. You’ll probably have to pass the data through a filter like escapejs
or safe
.
Alternatively you could do something like
{% load static %}
<button id="create_table">Get data</button>
<div id="place_for_table"></div></div>
<script type="text/javascript">
var row_data = "{{ row_data }}";
</script>
<script src="{% static 'javascript/scripts/create_table.js' %}">
</script>
The issue with this approach is the scope of variables as you may not want to declare things globally so it could be considered an easy approach, but not necessarily the best solution.
What I did was to include the javascript/jquery inside
{% block scripts %}
and use the the Django specific data as follows:
`
$.ajax({
type:"GET",
url: "/reserve/run/?ip={{ row_data }}",
dataType: "html",
async: true,
}).done(function(response) {
$("#Progress").hide();
$('#clickid').attr('href','javascript:ClearFlag()');
var win = window.open("", "MsgWindow");
win.document.write(response);
});
`
I’ve found a solution to avoid the extra typing of all the previous answers.
It’s a bit hacky:
Just transform you myjavascriptfile.js
into myjavascriptfile.js.html
and wrap the code in a <script>...</script>
tag. Than include
them instead of linking them in your template file.
myTemplate.html
....
{% block js_footer %}
{% include "my_app/myjavascriptfile.js.html" %}
{% endblock js_footer %}
myjavascriptfile.js.html
<script type="text/javascript">
console.log('the time now is {% now "Y m d H:i:s" %}');
...
</script>
instead of writing the function in a separated js file, write it in script tags within your html page, so it can use the django template language