Accessing Django template {{Variable}} from JavaScript - javascript

I tried to access django template variable in html page inline javascript, it works fine.
But if I include js using <script src="..> then it dont work.
Is this limitation or I'm doing something wrong?
I really appreciate your help.

The included Javascript isn't processed by the Django template processor on the server, so that won't work. If you need to pass information through the template to included Javascript files, have your template create a small <script> block wherein some global variable is declared to contain those template variables. Then, your pure Javascript file can get the values by looking for the global object created by that <script> from the template.

Pointy's answer is correct. I often find this filter useful for that situation:
#register.filter(name='json')
def _json(obj):
#remember to make sure the contents are actually safe before you use this filter!
return safestring.mark_safe(json.dumps(obj))
then in a <script> tag I can just do something like this:
window.g_details = {{ details|json }};

Related

Thymeleaf syntax is not working in java script file

I am using spring boot to provide data to thymeleaf.
var list = [(${listStudents})];
listStudents is a list of students with the help of which I populate data in HTML which is working fine but fetching the same list in java script using thymeleaf shows error in the above line as:
, expected.
I have added th:inline="javascript" attribute to script tag in HTML file as:
<script th:inline="javascript" src="home_script.js"></script>
Trying to solve this since yesterday.
Thanks in advance!
The , expected error is the standard JavaScript syntax error for var list = [(${listStudents})];. To handle this, Thymeleaf supports placing its inline expressions inside JavaScript comments:
var list = /*[[${listStudents}]]*/ [];
Because the Thymeleaf expression is in a JS comment, note how we have to provide a default (visible) JS value, to keep JavaScript from raising a different syntax error. I used [] because you have a list. You could have used '', or null or whatever is most suitable. Assuming your Thymeleaf is rendered correctly, this extra syntax will be ignored.
See JavaScript natural templates for details.
However, I do not think this will completely resolve your problem, unless you have already configured a JavaScript template resolver in your application.
You are using this:
<script th:inline="javascript" src="home_script.js"></script>
First of all, the th:inline="javascript" portion has no effect, because your JavaScript code is in an external file: home_script.js (i.e. it is not embedded in your HTML file).
If you want Thymeleaf to process the Thymeleaf expressions in that separate JS file, you have to tell Thymeleaf to explicitly process external JavaScript files (just like it processes HTML files).
You probably only have a HTML resolver - and your JS code is not embedded in your HTML file - it is in its own separate JS file. See this demo application which shows how to set up what I think you may need.
Alternatively you can simply embed your JS directly into the <body> of your HTML file, and don't use an external JS file:
<body>
<script th:inline="javascript">
var list = /*[[${listStudents}]]*/ [];
</script>
</body>
If you still need to use an external JS file, you can assign all your Thymeleaf-generated variables inside your HTML file (like the example above) and then pass these variables as function parameters into the various JavaScript functions in your JS file.
Using this approach means your JS file does not need to contain any Thymeleaf expressions - it just receives the rendered values from the JS fragment in your HTML file.
You should use [[${listStudents})]] (so 2 square brackets, not using round brackets)

Preferred way to dynamically change variable in Javascript using Python/Flask framework

I am relatively new to HTML/Javascript, and I have a need which I am sure is common, but I don't know the preferred/standard way to handle it.
Basically, I have a web page with Javascript/jQuery code to use AJAX to dynamically change values on a page. I prefer not to encode the AJAX URL statically in the Javascript, but rather be able to pass the URL using Jinja from the Flask application.
So, for example:
$("#inputtext").autocomplete({
source: function (request, response) {
$.getJSON("{{ url_for('main.auto') }}?q=" + request.term,
function(data) { console.log('doing something in the function') }}
The key question is the Jinja template in the middle {{ url_for('main.auto') }}. This correctly renders the route for 'main.auto' if the Javascript code is embedded in the HTML file. However, I prefer to separate the JS from the HTML. So, I took the above code and put it in a separate .js file and imported it into the HTML like this:
<script type="text/javascript" src="{{ url_for('static', filename='js/memberSearch.js') }}"></script>
The above code is in the memberSearch.js file in this example.
When I import the JS code like this, Jinja doesn't render the {{url_for('main.auto')}}. I suppose that this is because Jinja goes through the HTML code first before the JS code is imported.
I found an answer by #martijn-pieters here that lists four methods of passing data from HTML to Javascript:
You can put that information in HTML tags. In the above example, your data is put in the repeated tags.
Or you could add data attributes to your HTML, which are accessible both to Javascript code and to CSS.
Or use AJAX to load data asynchronously; e.g. when you pick an option in the box, use Javascript and AJAX to call a separate
endpoint on your Flask server that serves more data as JSON or
ready-made HTML, then have the Javascript code update your webpage
based on that.
Or generate JSON data and put it directly into your HTML page. Just a some_variable_name = {{datastructure|tojson|safe}};
section is enough; then access that some_variable_name from your
static Javascript code to do interesting things on the page. JSON is a
(almost entirely a) subset of Javascript, and the way the tojson
filter works is guaranteed to produce a Javascript-compatible data
structure for you. The browser will load it just like any other
embedded Javascript code.
Of these methods, I have successfully used the first one by embedding the Jinja template in a element like this, for example:
<input type="hidden" id="urlForPdf" value={{ url_for('main.auto') }}>
Which allows me to access the rendered URL in my JS code.
I have also tried the fourth method of generating JSON directly in JS like this:
<script type="text/javascript">var url = {{ url_for('main.auto')|tojson}}</script>
which allows me to access the variable url from the JS function.
The answer I referred to above also mentions using Data Attributes. I haven't tried this, but I believe it would work as well.
My question, then, is simply whether there is a preferred way of doing something like this? It seems that this must be a very common scenario and I assume that there is some more-or-less standard way of handling this. I'm just not sure which of the four possible solutions is preferred, or if perhaps there is another way altogether.
Thanks in advance for any light you can shed on this.

JSP variable initialization is happening after JS runs

I'm initializing a JSP string inside a Liferay portlet:
String json = "{}";
// returns json
json = LiferayPortlet.makeCurlCall();
...
<script>
$(window).load(function(){
//initialize js variable
jsData = "${json}";
// initialize the page
initializePage(jsData);
});
</script>
The issue I'm having is that LiferayPortlet.makeCurlCall(); is returning json, but jsData is not being initialized to it, instead its being set to "". Is there a way to initialize jsData to the json that is being returned from the function above?
Don't do it
You cannot initialize a JavaScript variable with a scriptlet or JSTL. The Java code is executed on the server and will not execute in top down order on your jsp page.
While I don't recommend this you can use the following
<script type="text/javascript">
var message = '<c:out value="${json}"/>';
</script>
That will technically work - however I want to stress that I do not recommend this. Maybe you can explain exactly what you are trying to accomplish and we can recommend a more optimal way of doing it.
JSTL v. Scriplets
You might also have a scope issue using JSTL and scriplets together indiscriminately. They are of different scopes. JSTL works with the following scopes.
page
request
session
application
Scriplets are in the page scope always. So while your code doesn't contain this issue it most likely will be something you will encounter.
Recommendation
If you are using Liferay, I suggest you learn Alloy UI (a JavaScript library) and become comfortable with their AJAX modules. Generally, when I see the code you posted, it is better to have an AJAX function that makes a GET call to your portlet for the JSON when it is needed.

jinja2 variables in javascript

If I have written jinja2 variables in javascript, for example
var array = [{{count}}...
and it works, will it work even if I move the code to a separate js file? Is there anything else I need to know about this practice?
You can certainly create a Jinja2 template that contains Javascript with Jinja2 variables, render that into a JavaScript file, and serve it to your users. Jinja2 doesn't care what kind of file you are rendering.
An important consideration is that you are changing a static file to a dynamic file. A typical Javascript file is static but you are now making it dynamic which puts additional load on your servers.
A typical solution is to use static JavaScript but render JavaScript data into your HTML page that the JavaScript file can access.
I came across this looking for the same kind of solution, and it was pointed out to me somewhere else that the data attribute in HTML is a good solution here as well.

Using gsp layout declared variable in javaScript file that is being loaded in the same page

I recently started learning grails and I am trying to use a gsp variable declared in the layout of the page as:
<g:set var="abtestType" value="newSearchBar" />
in the js file that is being loaded on the same page. Things that I have tried:
alert(${abtestType});
alert(<%=abtestType%>);
alert("abtestType:"+abtestType);
but its showing error as variable is not defined. Probably I am trying to fetch it in wrong way, need help regarding this.
Even thinking about doing so neither makes sense nor applicable.
Reason for such statement is that when a gsp page is rendered to an html page, it replace grails tags with appropriate html tags or value. Similarly it replaces the ${} or <%%> with html or javascript or whatever that goes on front-end.
Hence the code that you have tried could have worked fine if you were having those javascript code lines in the gsp itself but as you have called externalised js file it actually don't know anything about gsp or jsp or any other Language's front-end support.
The one way of doing that if using global variable in javascript. e.g.
declare abtestType above like below:
<script>
var abtestType = "${abtestType}"
</script>
Now you have access to global variable abtestType in your javascript.
Use it in your javascript but remember now you need to have this variable iff the code using it is called otherwise very same error would you get i.e. variable is not defined
There is another way that I found in this post but is a manipulation actually.
Is there any analogue in Javascript to the __FILE__ variable in PHP?
Also, another good links is
Pass vars to JavaScript via the SRC attribute
Hope it helps!

Categories

Resources