Background:
I am using PlayFramework to create a webapp (workflow) system which uses the Twirl template engine (scala based) to create my views.
Problem:
I need to store JavaScript variables inside of my template (which renders HTML), where in a separate JS file(s), I will perform operations on later.
Any existing solutions?
This can be done according to these SO questions I found:
This one creates a map where data is stored in and later retrieved.
This one creates a simple example of storing a variable in an inline script tag to use later
Finally, this one uses a more concrete example of storing data in data structures in the template and accessing the data structures in JS after being parsed.
The example created by an active SO contributor, Biesior, helping many developers with Play! Framework questions
To summarise what should be done:
Pass in some data into template
#(myData: DataObject)
Add data passed in an into a script tag with a JS name
<html>
<body>
<script>
let someJSDataName = #myData
</script>
</body>
</html>
Use in JS / Google Chrome Dev console
someJSDataName.toString
This should display some result!
But what is the problem?
Let me show you.
Rendered Html:
//...
<div class="BoxMediumBlue" style="padding: 20px;">
<script>
let facultyDepartments = {Science=[Computer Science, Physics], Biology=[Zooology]};
</script>
<br>
<div class="container-heading">
//...
When attempting to access this data in my Google Chrome dev console:
facultyDepartments
VM1209:1 Uncaught ReferenceError: facultyDepartments is not defined
at <anonymous>:1:1
Just an FYI, using var makes no difference
Am I doing something wrong?
Your definition of facultyDepartments uses syntax that the JS engine doesn't understand:
let facultyDepartments = {Science=[Computer Science, Physics], Biology=[Zooology]};
Objects should contain key-value pairs, where the keys and values are separated by :s, and where the keys and values, when strings, have delimiters like " or '. You should try to get the template to render JSON instead, for example:
let facultyDepartments = {"Science":["Computer Science", "Physics"], "Biology":["Zooology"]};
console.log(facultyDepartments.Science);
(JSON is technically a way of formatting strings, but inserting a JSON string without delimiters so that it's parsed as an object literal works too)
Related
This question already has answers here:
JavaScript raises SyntaxError with data rendered in Jinja template
(3 answers)
Closed 6 years ago.
I am sitting on a Flask based webapplication. In theory I want to load a JSON file from disk and give it to javascript on the website.
def getData():
check_for_update()
with open(LOCAL_file,"rb") as myfile:
data = json.load(myfile)
udate = data["today"]
return (udate, data)
then I send it to the page with
return render_template('./index2.html', udate = thisdata[0], data = json.dumps(thisdata[1]))
Now on the page I simply try
<script>
var myjson = JSON.parse({{data}})
</script>
which then results in something like this
This can't not be parsed.When I copy and paste it it works fine, and python does not complain either.
data is HTML escaped, because Jinja2 by default escapes everything to be safe to embed in an HTML page.
It's much better to not encode to JSON in the view, do this in the template instead, and use the Flask tojson and safe filters.
So in the view pass in thisdata[1] unencoded:
return render_template(
'./index2.html', udate=thisdata[0], data=thisdata[1])
and in the view:
<script>
var myjson = {{ data|tojson|safe }};
</script>
tojson produces JSON data that is also HTML-safe (albeit with " quotes, so it is not suitable for embedding in a HTML tag attribute), and the safe filter can be used to switch off the HTML-encoding. There is no need to use JSON.parse() here, the resulting JSON produced by tojson is a strict JavaScript subset.
See the JSON Support section in the API documentation:
The htmlsafe_dumps() function of this json module is also available as filter called |tojson in Jinja2. Note that inside script tags no escaping must take place, so make sure to disable escaping with |safe if you intend to use it inside script tags[.]
and the Standard Filters section of the Flask Templates documentation:
tojson()
This function converts the given object into JSON representation. This is for example very helpful if you try to generate JavaScript on the fly.
This works:
var editor = $("#htmlEditor").data('ejRTE');
The question is what does .data('ejRTE') do?
It retrieves the widget which is part of this html:
<textarea id="htmlEditor" value.bind="entity.content"
ej-rte="e-width:100%"
ref="textArea"
style="height: 220px"></textarea>
How do I retrieve it without jQuery.
jQuery.data() Store arbitrary data associated with the specified element and/or
return the value that was set.
So basically the widget stores some data in the element htmlEditor indexed ejRTE, I bet it is a custom object used by this tool.
var editor = $("#htmlEditor").data('ejRTE');
then editor will hold the object stored by the widget for this element
If you set data like this $(#myWidget).data('foo', 'myFoo') then jQuery will create an object called 'jQuery224059863907884721222' on myWidget which it uses to store the value.
I am guessing that the number is an arbitrary datetime value.
I stepped through the jQuery code, and it's not practical to replace it. I thought it might be just a line or two of code.
I have inherited some code that uses the Play! framework which has scala.html files that have javascript in them. Play! and scala are all new to me.
One of the javascript functions does a post and gets back a JSON object. It then loops through the JSON object and creates an array.
var myArray = [];
function createArray(){
$.post('/createArray', $('#arrayForm').serialize()).done(function( data ) {
var obj1 = JSON.parse(data);
$.each(obj1, function(idx, obj) {
myArray.push(obj.name);
});
});
return true;
}
It then uses this array (of strings) to create a text input field that does autocomplete using the data in the array.
I want/need to convert this text input to a select dropdown using the Play! #select but the options arg for #select wants a List object (or Map or Seq - just figured List would be easier since I already have an array of strings).
If I manually create the List object, it works fine.
#select(pForm("equipName"), options(scala.collection.immutable.List("Yes","No")))
The problem is I cannot figure out how to convert the myArray array to a List object which I can then pass to the #select options.
I have found a lot of posts that talk about converting a scala List to an array but can't find a way to go the other way. I am hoping it is an easy thing that I can't seem to figure out.
Thanks in advance for the help.
You can not do that. And more precisely - you do not want to do that.
So basically your play application run on server. In your Play application all those .scala html files are compiled to generate some functions.
Now, when a play application receives a request from a client browser, it gets mapped to some controller by by router. The controller does some processing and finally take one of these above functions ( lets say for index.scala.html we get views.html.index ) and call this function with some parameters.
These functions returns some text which is then sent to the client's browser as HTTP response with response header Content-Type:text/html; charset=utf-8 which tells the browser to treat this text as html.
Now, the browser renders the html which has embedded JavaScript and hence runs the JavaScript. So... basically your JavaScrpt code does not exist on server... for play all of it is just text.
Both of these Scala code and JavaScript code are executed at very different times, at different computers and in different environments hence you can not do whatever you are saying.
In an app, made with TideSDK; i assign a global variable (shocking I know) to a the JSON parse of a string stored in Titanium.App.Properties:
var workbookArray = JSON.parse(Titanium.App.Properties.getString('workbookArray'));
workbookArray is an array of objects.
And then on the unloading of a page, I assign Titanium.App.Properties string the value of workbookArray, which may have been changed by whoever has used the app:
Titanium.App.Properties.setString('workbookArray', JSON.stringify(workbookArray));
Each time I open the app, however, I'm told that JSON was unable to parse the first code snippet (initializing workbookArray).
Aside from this issue, I don't expect to use the app Properties API for my storage needs in the longterm, I wish i could use indexedDB with titanium. SQL is an option, but is a little messy when it comes to objects. Any other suggestions for a database solution?
Try getList and setList
http://docs.appcelerator.com/titanium/latest/#!/api/Titanium.App.Properties
What is stored in the list?
So I am trying to store an array of objects into localStorage, as follows:-
EDIT: The following is part of a function that is called in a loop.
c = [{"name":nameDOM.value,"add":+addDOM.value,"town":townDOM.value,"post":postalDOM.value,"mob":mobDOM.value}];
cData = cData.concat(c);
localStorage.setItem('cData', cData);
However, after a page refresh, when I try to access data from the objects, it is apparently undefined. Accessing data from the objects is fine before a refresh.
I am accessing the data in the following manner:-
//Table code omitted.
var text = document.createTextNode(""+cData[i].name+", "+cData[i].add+", "+cData[i].town+", "+cData[i].post+", "+cData[i].mob+"");
I have been trying to debug the problem using Chromes Javascript tools, as well as inserting alerts into various places to monitor the state of the variables; still undefined.
You've made an oopsies. Try:
c = [{"name":nameDOM.value,"add":+addDOM.value,"town":townDOM.value,"post":postalDOM.value,"mob":mobDOM.value}];
cData = cData.concat(c);
localStorage.setItem('cData', JSON.stringify(cData));
They difference being that you are turning your array of objects into a json string that can be parsed later by your code using:
eval(localStorage.getItem('cData'));