3

I'm currently having an issue with getting javascript and python to communicate in web2py.

controller:

def testDB():
        a=[]
        a.append('a')
        a.append('b')
        a.append('c')
        return dict(m=a)

(Eventually this will be replaced with an array of DB rows) Currently I'm trying to assign the values in m to an array in javascript. I've tried this a few ways:

var t="{{=m}}";

Returns about 43 meaningless characters. Then I tried:

var t= new Array(); var i=0;"{{q=0}}"
"{{i=len(message)}}"
i="{{=i}}";
for(q=0;q<i;q++,"{{q=q+1}}"){
t[q]="{{m[q]}}";
}

Which failed because the python q variable would reset every time the loop did, which is the heart of my problem. I also tried using pop:

for(q=0;q<i;q++,"{{q=q+1}}"){
    alert("{{m.pop()}}");
    }

But the array keeps resetting again at the start of the loop, so it keeps showing the same variable. Is there a simpler way to copy the arrays, or to stop the python variables resetting, or even simply to plug the javascript q variable into "{{m[q]}}" instead?

From what I've found, the problem comes from python being server side so you can't assign javascript values to it's variables, but I'm not sure what that has to do with the loop part of it (If I do the same outside a loop, the values do not reset). The common solution seems to be to use ajax or json, but I'd like to avoid that if possible. Thanks

cwallenpoole
  • 79,954
  • 26
  • 128
  • 166
James
  • 53
  • 1
  • 6

3 Answers3

6

In web2py (or any server-side template language), you cannot mix server-side Python code with client-side Javascript code the way you have. When the page is requested, the Python in the web2py view is evaluated, and a pure HTML page (with Javascript code included) is generated and returned to the browser. The browser doesn't get any of the Python code and cannot execute a mix of Javascript and Python.

The web2py view only inserts text/code into the page when you have {{=some_value}} (note the equals sign). So, things like {{m[q]}} have no effect. If you want to see what the browser is receiving from web2py, look at the page source in the browser -- it will show you the end result of the HTML/Javascript generated by your view.

As for your particular question, you can use response.json() to convert your Python list to a JSON object. However, if you include that as is in the view, it will escape all the quotes, so you have to pass it to the XML() helper to avoid the escaping. Something like this:

var t = {{=XML(response.json(m))}}
Anthony
  • 25,466
  • 3
  • 28
  • 57
  • Thanks a bunch, that works perfectly. Now I'll have to figure out how to get it to accept DB rows – James Sep 24 '11 at 03:21
2

Anthony's answer doesn't work on web2py 2.9.12 or above.

To assign python variable value to javascript varible, first convert it to json in controller and then pass to view And in view, use XML() to assign it to javascript varible so that it is not escaped

Controller

from gluon.serializers import json

def index():
    array = [1, 2, 3, 4, 5]
    dictionary = dict(id=1, name='foo')
    return dict(array=json(array), dictionary=json(dictionary))

View

<script>
    var js_array = {{=XML(array)}};
    var js_dictionary = {{=XML(dictionary)}};
</script>

Other solution is use ASSIGNJS helper

Controller

def index():
    array = [1, 2, 3, 4, 5]
    dictionary = dict(id=1, name='foo')
    return dict(array=array, dictionary=dictionary)

View

<script>
    {{=ASSIGNJS(js_array = array)}}
    {{=ASSIGNJS(js_dictionary = dictionary)}}
</script>
Community
  • 1
  • 1
Gaurav Vichare
  • 1,143
  • 2
  • 11
  • 26
2

Use the json module:

>>> import json
>>> s = json.dumps(range(5))
>>> print repr(s)
'[0, 1, 2, 3, 4]'
>>> print json.loads(s)
[0, 1, 2, 3, 4]
>>>
Roshan Mathews
  • 5,788
  • 2
  • 26
  • 36
  • And how would I use that to put the values of m into a javascript array? – James Sep 23 '11 at 05:39
  • `json.dumps(py_list)` will give you a JSON array. Pass it on to the browser. – Roshan Mathews Sep 23 '11 at 05:46
  • This doesn't work with web2py. Sorry recognize that this is an old thread. Felt I should mention it though. Have been trying the same thing and you get `&quot` instead of quotation marks in the JSON string in the view – Tahnoon Pasha Dec 07 '14 at 01:51