I currently use
<script type="text/javascript" src={% static 'app.js' %}></script>
to retrieve my JavaScript file.
However, app.js tries to use Jinja2 tags with are not translated when I import my script in this fashion.
An example, of a line causing an error in app.js would be
$('#tag').click(function() {
window.location.href = "{% url 'Project.views.views.viewname' %}";
});
How do I force {% url 'Project.views.views.viewname' %} to be translated to a url if it is located in an external JS file?
Related
As we know in Django framework we can generate the HTML page based on some predefined template files.
Inside those templates we can use and some specific django keywords/operators/functions.
Like:
{% block stylesheets %}
<link href="{% static 'js/jquery/jquery-ui.css' %}" rel="stylesheet">
<link href="{% static 'vendor/chosen/chosen.css' %}" rel="stylesheet">
{% endblock stylesheets %}
But most important things which I want to touch in this question are related to tag 'translate'
"{% trans 'List of all available masters' %}"
So I can be sure that the final content of my page will use some predefined language.
And the places where I am using such tags are different: "simple" html content with / and etc tags AND inline javascripts blocks. Like:
<script type="text/javascript">
$('#datepicker_value').on('change', function(){
....
var dialog = BootstrapModalWrapperFactory.createModal({
title: '{% trans 'Extended information about the event' %}',
message: '<pre>'+JSON.stringify(info.event.extendedProps.description, null, 4)+'</pre>',
buttons: [
{
label: '{% trans 'Close' %}',
cssClass: "btn btn-secondary",
action: function (button, buttonData, originalEvent) {
return this.hide();
}
}
]
});
....
</script>
So my main question here is such:
HOW correctly I can move ALL <script>...</script> blocks from html template into the external JS file?
To keep all the functionality of the django framework working! And my 1 variant was - I should use the same technique which I use for generating HTMLs with Django framework abilities. But maybe in a little shorten variant: Right inside the views.py file - CAN I somehow correctly generate on the fly full content of GLOBAL.js file which will contains ALL ... blocks from html template - where they all were previously stored.
And in a such manner - that standard django template engine can convert all {% ..... %} placeholders in a correct real content BEFORE the full content of GLOBAL.js will be generated and given out. And especially the content of translatable placeholders!!! Well, then in the HTML page template I can insert a call to a special command that can display the contents of this script at the moment the page is rendered by the browser on the client side. Something like:
<script type="text/javascript" src="{% url 'GLOBAL.js' %}"></script>
Am i right? If yes - how I can do that step-by-step? Or maybe there is something new and more logical way?
Django version is the latest one!!! 3.*
P.S. Also I've faced with a problem of transferring script block with content like document.addEventListener('DOMContentLoaded', function(){...}); Looks like such event handlers can't be moved out to the separate JS file from HTML page((
There is no reason you couldn't use Django template tags inside Javascript files (or any other filetype for that matter). As an example, here's is a view that returns rendered Javascript:
from django.shortcuts import render
def render_javascript(request):
return render(request, 'myapp/global.js', {})
If you hook this view into your urlpatterns like this:
urlpatterns = [
path("js/global.js", render_javascript, name="globaljs"),
]
You can then use the {% url %} template tag to refer to it from your HTML templates like this:
<script type="text/javascript" src="{% url 'globaljs' %}"></script>
Now when your browser requests js/global.js, the Django view will take the template myapp/global.js, process it with the templating system, and return the rendered template.
So I was trying to add an audio recording function to my website developed with django.
I wanted to do something similar as https://github.com/addpipe/simple-web-audio-recorder-demo so I started by trying to run it without modification.
I took the same html as in the git linked above, put the js/ folder in my static/ folder, and simply changed the following lines (index.html, line 32-33)
<script src="js/WebAudioRecorder.min.js"></script>
<script src="js/app.js"></script>
for
{% load static %}
<script src={% static "js/WebAudioRecorder.min.js" %}></script>
<script src={% static "js/app.js" %}></script>
These js files load correctly, but the problem is that when I click record on my website, I get a "GET /myapp/record/js/WebAudioRecorderWav.min.js HTTP/1.1" 404 error in my django server.
WebAudioRecorderWav.min.js is called within WebAudioRecorder.min.js. I tried to use the {% load static %} trick in the js file, but it doesn’t work.
What would be the correct way to work around this?
Thanks in advance.
You should use the workerDir setting to set the correct path to the other imported js files. Probably your recorder is initialised in app.js, where you cannot use template tags like {% static %}. The best way is to create a global variable in your template before loading app.js:
In your HTML template:
<script>var jsFilesPath = "{% static 'js/' %}"</script>
<script src="{% static 'js/app.js' %}"></script>
In your app.js:
if (typeof jsFilesPath !== "undefined") {
audioRecorder = new WebAudioRecorder(sourceNode, {
workerDir: jsFilesPath // must end with slash
});
}
So for those of us who use Python and Django framework to develop a website, there is this awesome tool known as jinja which can be used as a template engine. For example:
Instead of hard-coding an import like this:
<script src="assets/js/onebutton.js"></script>
We can do this:
<script src="{% static 'assets/js/onebutton.js' %}"></script>
In this case, it automatically searches for a folder named static and goes inside to look for the needed code.
But why isn't it possible to use jinja template in Javascript.
For example:
homepage.html
<script src='whatever.js'></script>
<p>Another example</p>
<button id="clickme"> click me </button>
whatever.js
$(function()
{
$('#clickme').click(function(){
$.ajax({
headers : {'X-CSRFToken': getCookie('csrftoken')},
type: "POST",
url: '{% url "func" %}', //<--Problem arise here
datatype:"json",
data: {},
success: function(data){
var new_template = '<h1> %firstmsg% </h1>';
var new_frontend = new_template.replace('%firstmsg%',data.message);
console.log(new_frontend);
document.getElementById('wor').innerHTML+=new_frontend;
}
});
}
}
Django would recognize the url in the AJAX request as /'{% url "func" %}' instead of /func
The only way to solve this is to move the entire code from whatever.js into the homepage.html in a <script></script> block.
Perhaps we need to import something for Jinja templating to work?
<script src="{% static 'assets/js/onebutton.js' %}"></script>
In this case, it automatically searches for a folder named static and goes inside to look for the needed code.
This is inaccurate. All it does is it converts the given path to the static path provided in your settings file like this - /static/asssets/js/onebutton.js. That is it. Django or Jinja2 doesn't go through the folder and look for the file. It doesn't even care if file exists or not.
Later, the browser automatically fetches this file from the server when it receives the html document.
Coming back to your original questions about why you can't use Jinja2 or Django template syntax in your JS files. Well, you can. But you'll have to render your JS files from your views.
Now, I'm sure you're using the render function to return a template from your views. But what does it do?
The render function converts the django specific template tags into proper html content.
So, if you're using django's or jinja's template syntax in your js files, you'll have to render your js files too. But that seems like a bad idea. Instead, you can create some global variables in your html files, and use them in your js files.
<!-- define required variables in template -->
<script>
var URL = '{% url ... %}';
var OTHER_VARIABLE = '{{ other_variable }}';
</script>
<!-- include your js files -->
<script src="/path/to/file.js"></script>
I have a workaround for this kind of necessities. Put your js code inside <script></script> tag and save it as html file inside templates folder.
Now you can include your html file to your page.
{% include 'myapp/js_code_with_jinja.html' %}
All jinja code will work as expected.
How to import inside JavaScript files and using Django to load another js.
Statements like these don't work:
import { PolymerElement, html } from '{% static "#polymer/polymer/polymer-element.js" %}';
import '{% static "#polymer/app-layout/app-drawer/app-drawer.js" %}';
And also these too:
import { PolymerElement, html } from '#polymer/polymer/polymer-element.js';
import '#polymer/app-layout/app-drawer/app-drawer.js';
// myapp-shell.js
import `${static_path}`;
//....
<!DOCTYPE html>
<html lang="en">
<head>
{% load static %}
<script src="{% static 'node_modules/#webcomponents/webcomponentsjs/custom-elements-es5-adapter.js' %}"></script>
<script src="{% static 'node_modules/#webcomponents/webcomponentsjs/webcomponents-loader.js' %}"></script>
<!-- Loading app-shell -->
<script>
var static_path = '{% static "my-icons.js" %}';
console.log(static_path);
</script>
<script type="module" src="{% static 'mycomponents/myapp-shell.js' %}"></script>
</head>
<body>
<myapp-shell></myapp-shell>
</body>
</html>
Is there is a way to do that without bundling the code in one big file, nor calling all files may be needed in the html file.
Thank you
It's definitely not right to use Django template tags inside your JS files, since they will not be processed by Django's template loader. I'd suggest either:
(a) Use only relative path imports in your JS files.
or
(b) Set up your Django STATICFILE_DIRS setting to include the node_modules directory and setting STATIC_ROOT to something like '/static'. Then do your module imports as import { x } from '/static/path/to/module'.
EDIT: Grammar
I searched that for a long time and the way I found to do that is:
inside your mains script use this function.
function include(file) {
var script = document.createElement('script');
script.src = file;
script.type = 'text/javascript';
script.defer = true;
document.getElementsByTagName('head').item(0).appendChild(script);
}
then load your script like this:
include('/static/js/your_js_file.js');
don't forget to register your static files directory in settings.py
example:
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "your_folder of library"),
]
Mabe you can use a global variable at top of your js importations, because static it's only for django template, you can do something like this inside your template file:
<script>
var static_path = '{% static "#polymer/polymer/" %}';
</script>
end then import your js files using this path
import { PolymerElement, html } from `${static_path}/polymer-element.js" %}`;
i set it up STATICFILES_DIRS STATIC_URL in settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'projectName', 'static'),
]
and i want to use javascript files in template but it is not working.
js file path is app/static/app/new.js
and i used it in template using this code
{% load static %}
<script type="text/javascript" src="{% static "app/new.js" %}">
$(document).ready(function(){
alert(1);
new_function();
});
</script>
function in new.js as well as alert does not working.
If I delete the src part in script tag, the alert works fine.
I can see the new.js script by accessing the path that appears in the chrome developer tool.
What did I do wrong?