Friday, March 14, 2014

Python Flask - passing JSON to a template in a variable

I ran into a problem in my Python Flask app. I wanted to store some JSON-formatted data in a Python variable, and use JQuery's parseJSON function to consume that data inside a Jinja template. When I tried to parse the JSON in the template, a JavaScript error resulted. I figured out why, and how to work around it.

By the way, the same problem occurs, and the same workaround applies, whether you pass the variable in the call to render_template, or use a session variable.

Here's a copy of my first attempt at the code...

Python:

def index():
        return render_template('viewer_type.html', myVar='{"abc": "123", "def": "456"}')

JavaScript:

<script src='jquery-1.10.0.min.js></script>
<script>
        var myVar = "{{ myVar }}";
        var myJSON = $.parseJSON(myVar);
        prompt("abc", myJSON.abc);
</script>

This failed. prompt never executed, and Chrome's JavaScript console reported this error.

Uncaught SyntaxError: Unexpected token &

I realized that the contents of the variable were being encoded when Flask passed them to the template. Adding this line of JavaScript...

prompt("myVar", myVar);

... revealed that my JSON had turned into:

{&#34;abc&#34;: &#34;123&#34;, &#34;def&#34;: &#34;456&#34;}

Thanks to this helpful post on stackoverflow, I found a convenient way to decode the encoded text in JavaScript. I encapsulated that in a function:

function decodeJSON(encodedJSON) {
            var decodedJSON = $('<div/>').html(encodedJSON).text();
            return $.parseJSON(decodedJSON);
}


Then I just needed to amend my original JavaScript to call decodeJSON, so the whole thing looks like this:

<script src='jquery-1.10.0.min.js></script>
<script>
 function decodeJSON(encodedJSON) {
  var decodedJSON = $('<div/>').html(encodedJSON).text();
  return $.parseJSON(decodedJSON);
 }


 var myVar = '{{ myVar }}';
 prompt('abc', decodeJSON(myVar).abc);
</script>


Success! The expected output, 123, was displayed, and there were no more errors in the JavaScript console.

4 comments:

  1. That is really helpful.
    have you ever tried passing variable with index to call from javascript?
    for example in this case,
    var myVar[i][j] = "{{ myVar[i][j] }}";
    where i,j are variables in javascript.

    ReplyDelete
  2. I randomly stumbled across this solution and I found it useful. Thanks kind sir.

    ReplyDelete
  3. An alternate method using standard Flask and Jinja capabilities can be found at [Passing a JSON object from Flask to JavaScript](https://stackoverflow.com/questions/42499535/passing-a-json-object-from-flask-to-javascript). Here is a summary:

    - In python, create `dict` with desired fields, say `temp`
    - Pass `temp ` directly to variable in `render_template` like so:
    - `render_template('', example_variable=temp)`
    - In `` read variable like this:
    - `var javascript_variable = JSON.parse('{{ example_variable | tojson | safe}}')`

    ReplyDelete
  4. Thank you very much. This trick works for me.

    ReplyDelete