I used to pass the variables in terms of dictionary to HTML template in Django without any problem. Now I plan to add some javascript into the HTML file, and use the same way "{{ }}" to obtain the object from dictionary in javascript. All the objects in the dictionary are actually strings.
In Django, the code is:
dataDict = {}
dataDict["time"] = json.dumps(",".join(timeList))
return render_to_response("xxxx.html", dataDict,\
context_instance=RequestContext(request))
And in HTML page and Javscript, I just want use a string variable to receive it and then resolve the information I want, and our code is:
var test = {{ time }};
But it seems Django cannot pass the data to the string variable in Javascript. So I have two questions:
Is there some special type of variable to pass the data from the Django to Javascript. Does JSON be possible? Or is it a must to convert string to JSON string in Django first before passing to Javascript?
How to use the delivered string in Javascript? Apparently just use var xx = xxxx; doesn't work. We think we can pass data but it seems cannot be processed.
Does anybody have some idea about it?
Thanks!
Maybe you just need to double quote it?
var test = "{{time}}";
Let's assume that dataDict['time'] = "1:30 PM, 2:30 PM". When your template is rendered it creates this text (verify it yourself w/ view source):
var test = 1:30 PM, 2:30 PM;
As you can see, this isn't valid JavaScript. When you double quote it it becomes this:
var test = "1:30 PM, 2:30 PM";
Similarly, you'll want to double quote your DOM elements with interpolated attributes, e.g., ... The Django builtin template filter docs have numerous examples of this.
It's important to keep in mind the difference between template evaluation / rendering time in your Python environment and JavaScript browser execution / evaluation time, especially when you try to pass data between the two.
Converting to JSON is recommended in order to prevent things such as spurious </script>-containing strings from causing issues with JavaScript. Assigning should be enough, since JSON strings look like JavaScript literals.
Related
I am developing a Spring Boot MVC application that uses Thymeleaf templates on the front end.
I am trying to bind a HashMap from my MVC model to a JavaScript variable in one of my Thymeleaf templates. This is what has been done so far: -
In my MVC controller class, I created a HashMap that represents user skills organised into categories. The Skill class is a data object containing name and id properties: -
Map<String, List<Skill>> skillsMap = new HashMap();
I populated this map with all the category and skill information and then added it to my Model: -
model.addAttribute("skillsMap", skillsMap);
On my Thymeleaf template in a script section, I am attempting to bind this HashMap to a variable. As a second step I then attempt to retrieve one of the lists from the map and assign to a second variable: -
var skillsMapMap = [[${skillsMap}]];
var adminList = skillsMapMap.get('Admin');
When I debugged this, I could see that the HashMap was being read and an attempt was being made to bind it to my JavaScript variable: -
var skillsMapMap = {Languages=[Python, SQL, PL/SQL, Java], Databases=[MySQL, Oracle, Mongo], Editors=[Word, TextPad, Notepad]};
This looked good at first glance and I could see that it contained all my data, but it was throwing the following error: -
Uncaught Syntax Error: invalid shorthand property initializer
Having researched this, I realized that this error was caused because Java does not by default serialize the map in valid JSON format and so the attempted bind to a JavaScript variable failed. So, instead of just adding the HashMap straight to the Model as in step 2, I added some code to use Jackson to convert it into a JSON String first: -
//Populate the map with all required data then....
String objectMapper = null;
try {
objectMapper = new ObjectMapper().writeValueAsString(skillsMap);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
model.addAttribute("skillsMap", objectMapper);```
This time When I attempt to bind this to my JavaScript variable, the object looks like this when I debug in my browser: -
var skillsMapJson = {"Languages_OD":[{"id":66,"name":"SQL"},{"id":67,"name":"PL/SQL"}], etc, etc};
The JSON now looks valid, but all the quotes are escaped and it now throws a different exception: -
```Uncaught SyntaxError: Unexpected token &```
I feel that if the JSON string contained actual quotes instead of " the Map would successfully bind to my variable. I would appreciate any advice as to how to deal with this. Many thanks for reading.
EDIT: Screenshot of error added below: -
I did eventually get round this problem and so am offering a solution in case it helps anyone else. However, I feel that the solution is a bit 'hacky' and so would welcome any further answers that improve on this or offer a more elegant solution.
The problem was in the way I was trying to retrieve my map from the Model and assign to a JavaScript variable. Initially, I was trying this: -
var skillsMapRawString = [[${skillsMapJson}]];
The trouble is that this way of referencing skillsMapJson forces JavaScript to treat it as an Object and it cannot deal with the encoding issue described in the original post when attempting to deserialize it into JSON. The above line therefore threw the exception "unexpected token &".
By adding single quotes around the object reference, JavaScript is forced to treat skillsMapJson as a String and not an object: -
var skillsMapRawString = '[[${skillsMapJson}]]';
The above variable assignment now works successfully, but we still have the problem that it contains encoded quotes which prevent it being parsed to a JSON Object. This is where it feels like a bit of a hack, because I got round this by doing a global replace on the String: -
var skillsMapJSONString = skillsMapRawString.replace(/"/g, "\"");
Having replaced the encoded sections that were causing problems before, the String can now be parsed as JSON: -
var skillsMapParsed = JSON.parse(skillsMapJSONString);
And finally, I have my map of lists successfully assigned to a JavaScript variable! :)
Symbols """ and similar are HTML escapes. So your info is HTML escaped. You can unescape it back by using class org.apache.commons.text.StringEscapeUtils from the library apache.commons/commons-text. The info found at: How to unescape HTML character entities in Java?
I'm programming in oTree (which is a Django based environment for social experiments) and I have the following problem. I defined some lists in Python and I'd like to import them and use them in an HTML template. If I print them in HTML I manage to see them without any problem, however, once I need to use them in Javascript, the program fails to read them and the single quotes of the elements of the list are converted in '.
The list is imported like this var filtered_elements = {{ array }};.
I think the problem is exactly here, as JS cannot work with them. Do you have any suggestion on how to do that? I considered using JSON, but since I'm quite new to programming, I cannot understand if it's just a waste of time or there is a simpler way out.
Thanks for your answers!
It sounds like your data is already JSON, otherwise you would be getting single quotes and u prefixes. So the only issue is Django autoescaping; you can disable it with the safe filter:
var filtered_elements = {{ array|safe }};
Your data should be JSON, instead of putting the Python list into the contact directly, put "array": json.dumps(array) in the context dictionary.
The JSON string doesn't need HTML escaping inside a tag, but it does need JS escaping! Otherwise some string may include something like </script><script>absolutely anything goes here... to run arbitrary JavaScript, if the JSON contains user data.
So use |escapejs:
var filtered_elements = {{ array|escapejs}};
I want to pass a dictionary from django view to a javascript file. The dictionary is built from a database populated by site users. What's the difference between these 2 methods in terms of security?
var mydata = JSON.parse("{{mydata|escapejs}}");
var mydata = {{ mydata|safe }};
Further, the doc at django says this for escapejs : This does not make the string safe for use in HTML. Could you show me an example of how it's unsafe & how can I make it safe.
For anyone coming across this in 2019, Django now provides a third option with the |json_script template filter. This filter takes care of properly serializing and escaping your Python object for use in HTML.
From the docs, using example data with unsafe characters my_data = {'hello': 'world</script>&'}:
{{ my_data|json_script:"my-data" }}
renders to
<script id="my-data" type="application/json">
{"hello": "world\\u003C/script\\u003E\\u0026amp;"}
</script>
You can then access this data in Javascript via
var value = JSON.parse(document.getElementById('my-data').textContent);
The following dictionary can break your page without proper escaping:
{'x':'</script><b>HELLO</b>'}
Inside tags, you can json.dumps it in your view and then use escapejs to stay safe.
(I believe the explanation means that if you want to show the output of json.dumps in HTML, let's say in a <pre> tag, just make sure it is escaped by not using safe or escapejs.)
I saw this string from an ajax call on some. It's clearly some sort of template. a:15 means there're 15 items in the {} expression. i:0 means item0, s:63: means the length of the string after it. I google for a while, but could not find any JS template engine that can take input like this one. It is possible they use Regex to parse the data.
a:15:{i:0;s:63:\"http://ww2.some.web/mw600/c01b8166jw1e4cf9fu2s0j20dw08v0v4.jpg\";i:1;s:63:\"http://ww4.some.web/mw600/c01b8166jw1e4cf9h284bj20dw0980ut.jpg\";i:2;s:63:\"http://ww1.some.web/mw600/c01b8166jw1e4cf9ksczrj20dw097n20.jpg\";i:3;s:63:\"http://ww3.some.web/mw600/c01b8166jw1e4cf9jvzymj20dw09840f.jpg\";i:4;s:63:\"http://ww2.some.web/mw600/c01b8166jw1e4cf9m9j9rj20dw0av41i.jpg\";i:5;s:63:\"http://ww3.some.web/mw600/c01b8166jw1e4cf9n1iq2j20dw0990ue.jpg\";i:6;s:63:\"http://ww2.some.web/mw600/c01b8166jw1e4cf9q062tj20dw09en17.jpg\";i:7;s:63:\"http://ww3.some.web/mw600/c01b8166jw1e4cf9sprglj20dw0a1djh.jpg\";i:8;s:63:\"http://ww1.some.web/mw600/c01b8166jw1e4cf9srts5j20dw097jui.jpg\";i:9;s:63:\"http://ww2.some.web/mw600/c01b8166jw1e4cf9wj84oj20dw08zn02.jpg\";i:10;s:63:\"http://ww1.some.web/mw600/c01b8166jw1e4cf9ws795j20dw09o418.jpg\";i:11;s:63:\"http://ww3.some.web/mw600/c01b8166jw1e4cf9xpixhj20dw0990ty.jpg\";i:12;s:63:\"http://ww3.some.web/mw600/c01b8166jw1e4cfa05o8fj20dw099die.jpg\";i:13;s:63:\"http://ww4.some.web/mw600/c01b8166jw1e4cfa0ah9yj20dw0aa76h.jpg\";i:14;s:63:\"http://ww3.some.web/mw600/c01b8166jw1ehttp://ww2.some.web/mw600/c01b8166jw1e4cf9fu2s0j20dw08v0v4.jpgcfa1jpsaj20dw099myq.jpg\";}
Looks like result of PHP serialize() function
You can use this js function to parse it.
This is PHP serialization format. You can unserialize with php:
unserialize(...)
And you'll get an array (with your example) if I'm not wrong
I'm since las update of GAE Launcher, it creates ID on datastore too big. Like 5330010158992982016, thats a problem to me, because on Javascript these numbers are rounded.
For example, on JS
> a = 533001015899298254645
> 533001015899298270000
an reading a JSON like [{"pk": 5330010158992982016, "model": " .... }],
$.getJSON(' ...
$.each(data, function(i,item){ ...
item['pk'] = 533001015899298270000 instead of 533001015899298254645
}
}
I'm not sure if I'll have the same problem on GAE servers. Any idea to limit ID size?
I'm using Django, but I'm having the same problem with Django and Google Models.
Update:
I found a solution that doesn't force you to change all javascript code of the project. In my case a lot. Like everybody says the best thing is to use de PK (or ID) as a string. But I as using django serializer and in my version and with JSON, the PK is set as a number. The easy solution is change this on the serializer class ( or create a new serializer wich extends original and change this ):
def end_object(self, obj):
self.objects.append({
"model" : smart_unicode(obj._meta),
"pk" : smart_unicode(obj._get_pk_val(), strings_only=**False**),
"fields" : self._current
})
self._current = None
Put strings_only to False. It makes the pk on the JSON goes with quotes. All the javascript code works without changes.
The question is... is there any other way to force django serializer to put it as String?
There is no way to read/store this number accurately in JavaScript, since in JavaScript numbers are actually double precision floats and the maximum is 900,719,925,4740,992.
You could
return the ids as string instead or
start the dev_appserver.py with an argument: --auto_id_policy=sequential
If for some strange reason Lipi's answer didn't cover you you can try another
approach which will be to cast all values to strings. So you would have
[{"pk": "5330010158992982016", "model": " .... "}],
I see you are using an Ajax call which probably means you won't need the following part but
For you Django variables instead of {{my_id}} you can make it a string like '{{my_id}}' if you are creating your JavaScript variables on render time.
The AppEngine team is aware of the issue and it will be resolved before the roll the update in production.