Safety of passing python list to javascript through jinja template - javascript

Just like the question posed here, I have a list in one of my Flask app's routes:
my_list = ['a', 'b', 'c']
The number of elements in the list depends on user input, but the elements themselves are strings from elsewhere in the program that the user doesn't have control over. I'm wondering whether it's safe to use this list in a <script></script> tag in my template. I'm using the python list as a javascript array using the tojson filter. This works in my development server just fine, but my code editor is pointing out 6 problems.
$(document).ready(function() {
var my_array = {{ my_list|tojson }};
for (let index = 0; index < my_array.length; index++) {
console.log(my_array[index]);
}
});
Property assignment expected. [line 2]
',' expected. [line 2]
',' expected. [line 2]
')' expected. [line 2]
Declaration or statement expected. [line 6]
Declaration or statement expected. [line 6]
Is this just erroneous flagging from my linter or do I need another way to use the python list in my javascript? Wondering whether this will cause any security issues when I deploy the app.

Related

Trouble accessing data from a JSON object that was originally a Python dictionary in Flask

Newbie here. I'm working with a database of apartment complexes and apartment units for an intro CS class and trying to build a web app using flask.
In application.py, I've got something like this:
locationdict =
{
"Complex A": [1, 2, 3],
"Complex B": [4, 5, 6]
}
JSONlocationdict = json.dumps(locationdict, sort_keys=True)
return render_template("start.html", JSONlocationdict=JSONlocationdict)
But nothing seems to work when I'm trying to access that data from the dictionary in JavaScript. The HTML page looks roughly like this:
<button onclick = "getUnits(this)" id="Complex A"> Complex A </button>
<script>
function getUnits(arg) {
var locationName = arg.getAttribute("id");
var JSONlocationdict = "{{ JSONlocationdict }}";
console.log(JSONlocationdict)
// In the console, this is what you see:
// {"Complex A": [1,2,3], "Complex B", [4,5,6]}
var obj = JSON.parse(JSONlocationdict);
console.log(obj); // this returns the error
// Then you see this in the console:
// Uncaught SyntaxError: Unexpected token & in JSON at position 1
// at JSON.parse (<anonymous>)
// at getUnits (start:88)
// at HTMLButtonElement.onclick (start:119)
var units = obj["Complex A"];
console.log(units);
// That last request to log to the console does nothing so far.
}
</script>
I've tried using different ways to convert the original dictionary into JSON like jsonify and json.loads() instead of dumps(). I have gone through piles and piles of entries on stackoverflow about SyntaxError: Unexpected token, but I can't seem to get anything to work. Any ideas??
The only thing that seems to work reliably is having two separate pages -- the first page where the user can select from a list of apartment complexes and then sending them to a second page where they can then pick the unit.
It would be nice if they could click a button for the apartment complex, and then have the list of units available at that complex get dynamically generated on the same page, though.
The Flask method render_template turns your JSON into a string, as you can see by logging the JSONlocationdict. Since it's rendering the string to HTML, it escapes the double quote characters, which is what your JavaScript is having the issue parsing.
To solve this issue, you'll need to un-escape the JSONlocationdict before passing it to JSON.parse. There are many ways to accomplish this, the accepted answer here should work in your case if you want to do it in the browser.
function htmlDecode(input){
var e = document.createElement('textarea');
e.innerHTML = input;
// handle case of empty input
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}
t = '{"Complex A": [1,2,3], "Complex B": [4,5,6]}'
x = htmlDecode(t)
console.log(JSON.parse(x))
Note: that in the above snippet, I had to edit the console.log response that was in your question to have the : after "Complex B" instead of the comma that was there.
If the result is actually what is in your question, then the JSON is not being formatted correctly by Flask, although your Flask code looks correct.
There are other ways that you can accomplish this task using AJAX and another Flask URL returning a jsonify response. There also are some template filters (like |safe) that do this, but depend on the template library you are using.

Javascript - List (array) length and getting an item from the list not working

I'm practicing JavaScript (just started this week) on vscode with the Quokka.js extension. Right now I'm initializing a list called "things" and trying to get the length of the list and getting some items out of it. This is my code:
var things = ['bananas', 'apples', 7];
things.length;
things[0];
The last two rows return nothing to me, not even "undefined".
How do I get vscode to return the length and the first object from the list using [0]? If it is not possible in vscode, what program should I use for learning JavaScript?
I also tried initializing the list as an array with
Array things = ['bananas', 'apples', 7];
but this does not seem to be allowed.
Moreover, for example the command
things.splice
seems to work in vscode.
Even if you're using Quokka, it's better to output using console.log. Quokka works very well with console.log.
Also try not to use var or declare array using Array. This is JavaScript, not Java.
// Do not use var
let things = ['bananas', 'apples', 7];
console.log(things.length);
console.log(things[0]);
// This will not work
// This does not make any sense either
Array things = ['bananas', 'apples', 7];
JavaScript Array is not Class or an interface by using which you can declare it's instances. JavaScript Array is a global object. There are no classes in JavaScript.

Org-mode JavaScript code block evaluation error when using console.log

I receive the error Invalid read syntax: "]" when using console.log to print values from JavaScript array objects inside of org file code blocks. Arrays that contain strings produce this error. Arrays which have just numeric values print to the console fine.
I am not sure why org-babel is having difficulty with console.log(). I tried checking the encoding of my org file as a first step. I verified my code using node.js by itself. Specifying a different interpreter (e.g babel-cli) to evaluate the code block produces the same error.
This works
#+BEGIN_SRC js
let myarray = [1, 2, 3, 4, 5];
console.log(myarray);
#+END_SRC
#+RESULTS:
: [1 (\, 2) (\, 3) (\, 4) (\, 5)]
This does not
#+BEGIN_SRC js
let myarray = ["a", "b", "c", "d", "e"];
console.log(myarray);
#+END_SRC
Is there something I need to do within my org config files? I am using Emacs version 26.1 on Windows 7 (build 1, x86_64-w64-mingw32). Node.js is version 10.15.3 .
Correction:
Where I have different lines trying to return/show values inside a code block, only the first return statement produces a result (return ends the immediate scope). What seems to work is process.stdout.write('yourcodehere'+ '\n');
Example:
Trying to use multiple return statements
#+BEGIN_SRC js
return ([0,1,2,3,4]);
return ([5,6,7,8,9]);
#+END_SRC
#+RESULTS:
| 0 | 1 | 2 | 3 | 4 |
Using process.stdout.write()
#+BEGIN_SRC js
process.stdout.write([0, 1, 2, 3, 4] + '\n');
process.stdout.write(["a", "b", "c", "d", "e"] + '\n');
#+END_SRC
#+RESULTS:
: 0,1,2,3,4
: a,b,c,d,e
: undefined
Previous Message:
Ok, I found a simple solution. Use return instead of
console.log().I tried the same example in Python and only got results when using return instead of print. So I tried the same with
my JavaScript examples using return as the final step and this works
great. The formatting of the array in the results block looks better
too.

How to pass an array of integers as a parameter from javascript to python?

I have a javascript code that obtains the value of several checked boxes and inserts their value (integers) into an array:
var my_list = $('.item:checked').map(function(){return $(this).attr('name');}).get();
I want to pass this javascript array to a python function as a paramter. This is how I am doing it right now, with ajax and jQuery:
$.ajax({
url : "{{tg.url('/foo/bar')}}",
data : {
my_list: JSON.stringify(my_list),
...
},
On the python side, I have this code, to get the parameters:
item_list = get_paramw(kw, 'my_list', unicode)
This works, but I am not receiving the array as an array of integers, but as a single string containing the "[", "]", "," and """ symbols, which I would have to parse and isn't the most elegant way of dealing with this whole situation I think.
How should it be done to receive a javascript array of integers as an array of integers in python (not as a string)?
The easiest way to send simple arbitrarily-structured data from Javascript to Python is JSON. You've already got the Javascript side of it, in that JSON.stringify(my_list). All you need is the Python side. And it's one line of code:
item_list_json = get_paramw(kw, 'my_list', unicode)
item_list = json.loads(item_list_json)
If item_list in your JS code were the Javascript array of numbers [1, 2, 3, 4], item_list in your Python code would be the Python list of ints [1, 2, 3, 4].
(Well, you also have to import json at the top of your script, so I guess it's two lines.)
The proper way to send multiple values for one key is
data: {
my_list: my_list,
},
traditional: true
...
Suppose my_list = [ 1, 2, 3 ], this results a query string / POST data
my_list=1&my_list=2&my_list=3
Without the traditional flag, the result would be
my_list[]=1&my_list[]=2&my_list[]=3
Which of course works, but in TurboGears you need to access it as my_list[].
On the other hand, I am not sure if the TG keyword argument passing work with multiple values; if you get a single value in kw, you can use request.getall('foo') to return all the foo keys as a list (possibly an empty list).

Node.js / JavaScript - JavaScript window variable breaking functionality

So on my Jade template, I am passing it a variable through the route which contains an array of names.
Here is the JavaScript from that template:
script(type='text/javascript')
window.teams = !{JSON.stringify(teams)};
teams contains the array I spoke about. Here is the JavaScript:
$(function () {
// Array of team names
var teamNames = [];
for(var i = 0; i < teams.length; i++) {
teamNames.push(teams[i].name);
}
var bracketTeams = [];
var teamMatches = new Array();
for(var i=0;i<teamNames.length; i+=2)
{
teamMatches.push([teamNames[i],teamNames[i+1]]);
}
var bracketData = {
teams : teamMatches,
results : [[
[ [1, 0], [1, 0] ],
[ [1, 0], [1, 0] ]
]]
}
$('#tournamentBrackets').bracket({
init: bracketData
});
});
Now for some reason, the functionality of the rest of the system completely breaks when I add in this JavaScript code. If I comment it out, then the rest of the system works fine, if I leave it in, buttons do nothing, links go nowhere, data isn't added (although the data is loaded, i.e a database of teams is listed). If I load the page, then uncomment the JS, the page works as it should though.
Any ideas what is breaking my system in this code? I just tried renaming window.teams to window.testName and it still broke. Really confused.
EDIT: HTML generated
http://pastebin.com/VdkEfANb
In Node.js, the window object probably does not exist. Node.js has a different global object than browsers do. In Node.js, the global object is actually named global. Unless you have specifically set up an object named window, you're probably getting a ReferenceError when you try to assign values to window.teams

Categories

Resources