Passing javascript data to web2py controller using json?

1,580 views
Skip to first unread message

brac...@gmail.com

unread,
May 6, 2013, 12:49:53 PM5/6/13
to web...@googlegroups.com
Hi all,

I'm trying to pass some data from javascript in the view back to the controller using json. I'm unsure how to do this correctly. I created a util.js:

function doPost(callback, data) {
 $
.post(callback, data, function(data){})
 
.done(function() { alert("Done!"); })
 
.fail(function() { alert("Failed!");})
}


function add_item(item_id, some_detail) {
 
var test = {};
 test
.item_id = item_id;
 test
.some_detail = some_detail;
 
 
var dat = {'test' : test};
 
var data = $.toJSON(dat);


 doPost
({{=URL('default', 'add_item')}}, data);
}

My default.py controller:


def add_item():
     data
= gluon.contrib.simplejson.loads(request.body.read())
     
// Do insert to db
     
print data
     
return dict()


My add button in the view:

<div>
    <{{=A('Add Me')}}
</div>



But I'm not sure how to tie this all together. The anchor tag needs an onclick which points to the function add_item() in util.js. The util.js should execute that function and do a post to the web2py controller, which would then do an insert into the database. Could someone help me out? Or is this not the ideal way of handling javascript data -> web2py?

Anthony

unread,
May 6, 2013, 2:06:34 PM5/6/13
to web...@googlegroups.com
I'm trying to pass some data from javascript in the view back to the controller using json. I'm unsure how to do this correctly. I created a util.js:


 doPost
({{=URL('default', 'add_item')}}, data);

Is util.js just a static JS file, or is it a web2py template served dynamically? If the former, then you cannot include web2py template code in it. If it is a template, then you probably need quotes around the URL (i.e., the quotes end up in the generated Javascript):

 doPost('{{=URL('default', 'add_item')}}', data);

Anthony

brac...@gmail.com

unread,
May 6, 2013, 2:13:13 PM5/6/13
to web...@googlegroups.com
I was having problems with putting web2py tags inside my util.js, so I moved it to the views instead:


function
 doPost(callback, data) {
 $
.post(callback, data, function(data){})
 
.done(function() { alert("Done!"); })
 
.fail(function() { alert("Failed!");})
}


function add_item(url, item_id, some_detail) {

 
var test = {};
 test
.item_id = item_id;
 test
.some_detail = some_detail;
 
 
var dat = {'test' : test};
 
var data = $.toJSON(dat);



 doPost
(url, data);
}

My button looks like this now:

<a href="" id="additem" onclick="add_item({{=URL('default', 'add_item')}}, {{item.id}}, 1);">Add Me</a>

But for some reason the add_item() in util.js is not being called.

Anthony

unread,
May 6, 2013, 2:26:02 PM5/6/13
to web...@googlegroups.com

<a href="" id="additem" onclick="add_item({{=URL('default', 'add_item')}}, {{item.id}}, 1);">Add Me</a>

Again, you're going to need quotes around that URL:

<a href="" id="additem" onclick="add_item('{{=URL('default', 'add_item')}}', {{item.id}}, 1);">Add Me</a>

Anthony

brac...@gmail.com

unread,
May 6, 2013, 3:23:51 PM5/6/13
to web...@googlegroups.com
Thanks Anthony, I had to move all the web2py tags out of the static util.js and I put them in <script> inside the view html. The quotes was the problem.

I can call my controller now and I see the json that was passed to it, which is great.

The current views code now looks like this:

<script>
    $
(document).ready(function() {
      $
('#additem').click(function() {
           
var url = '{{=URL('default', 'add_item')}};
           add_item
(url, {{=item.id}}, 1);
     
}
</script>



<a href="" id="additem">Add Me</a>

I have two questions now:

1. For some reason every click results in a javascript alert saying that it Failed, even though I can successfully do stuff with the data in the controller. Is there some sort of code I'm supposed to return through the controller to let jquery know that it's been successful?

2. To be safe, I'll sanitize the expected integers like so:

    def add_item():
         # get json data as 'data' ...
         item_id = int(data['test']['item_id'])
         other_data = int(data['test']['some_detail'])
   
         # Insert that item_id and other_data into db...
   
    But if I expected a string, how would I sanitize that string before using it to do something with the database? Is there a safe practice for this type of approach of getting data from json?

Anthony

unread,
May 6, 2013, 5:34:51 PM5/6/13
to

1. For some reason every click results in a javascript alert saying that it Failed, even though I can successfully do stuff with the data in the controller. Is there some sort of code I'm supposed to return through the controller to let jquery know that it's been successful?

Does the add_item() function have an associated view? If not, it may be generating an error (when a function returns a dict(), web2py looks for an associated view to execute). Instead, you can just return nothing.
 

2. To be safe, I'll sanitize the expected integers like so:

    def add_item():
         # get json data as 'data' ...
         item_id = int(data['test']['item_id'])
         other_data = int(data['test']['some_detail'])
   
         # Insert that item_id and other_data into db...
   
    But if I expected a string, how would I sanitize that string before using it to do something with the database? Is there a safe practice for this type of approach of getting data from json?

web2py already does escaping to prevent SQL injection (assuming you use the DAL, though not with .executesql()).

Anthony 

Derek

unread,
May 6, 2013, 5:46:14 PM5/6/13
to web...@googlegroups.com
You don't normally send just json data directly to a server. jquery will post data to a server to make it appear that a form was submitted. Generally as ""application/x-www-form-urlencoded"
So it's a key:value format which is better than json anyway.
If you did want to send a json string, you'd assign that string to a variable and have your post method use that variable (as you are doing). However, there is no need, unless you want to make your application go through those hoops for no reason...

Why is it you are sending json instead of the actual data in the first place? When you test it yourself, are you giving a json string?
Is jquery actually posting the string or is it unpacking the 'data' as json before submitting it?

Instead of reading the request body, why not reference the variable 'request.vars.data' , or request.post_vars.data ?

Alan Etkin

unread,
May 7, 2013, 8:12:20 AM5/7/13
to web...@googlegroups.com
But I'm not sure how to tie this all together. The anchor tag needs an onclick which points to the function add_item() in util.js. The util.js should execute that function and do a post to the web2py controller, which would then do an insert into the database. Could someone help me out? Or is this not the ideal way of handling javascript data -> web2py?

Everything you want to do here except the javascript event binding is encapsulated in this plugin:

code.google.com/p/plugin-clientapi

You only need to link the user click to a custom event to retrieve the form, submit it and get the server feedback.

brac...@gmail.com

unread,
May 7, 2013, 10:35:30 AM5/7/13
to web...@googlegroups.com
I'm not familiar with website design, so I wrote the util.js because I thought it might make things a bit simpler to handle. If I wanted a delete function, I would just add that in util.js and call the doPost() with the correct callback function. The doPost() would pass that to the respective callback function in web2py's default controller as a string. I use simplejson library to parse it to a python dict. 

Could you expand further by what you mean with sending "actual data"? I did the doPost() because all I wanted was a button which will pass information back to the server for processing. Most of the data isn't user-warranted, that is, the user doesn't have to enter anything. All the item properties (like the id) are already on that page so when the user clicks on "Add Me", all that's needed on the server is which item id it is dealing with as well as some other property. Since it's just two parameters which doesn't involve user input at all (the user shouldn't have to type in the item id just to add it), I thought using json would be easier than creating an entire form and submitting that way.

If the preferred 'web2py way' is to create a form for all data transactions between the controller and the view, could you provide a quick example of how to do it in this scenario with just one button (an anchor tag)?

brac...@gmail.com

unread,
May 7, 2013, 10:39:13 AM5/7/13
to web...@googlegroups.com
the plugin-clientapi seems neat. I kind of want to get my hands dirty by doing things myself first, but I'll definitely look into the plugin. Thanks!

brac...@gmail.com

unread,
May 7, 2013, 11:35:21 AM5/7/13
to web...@googlegroups.com
No, add_item doesn't have an associated view with it. I tried doing just a "return" and also tried omitting the return statement entirely. jquery still tells me it's failed.

On Monday, May 6, 2013 5:33:04 PM UTC-4, Anthony wrote:

1. For some reason every click results in a javascript alert saying that it Failed, even though I can successfully do stuff with the data in the controller. Is there some sort of code I'm supposed to return through the controller to let jquery know that it's been successful?

Does the add_item() function have an associated view? If not, it may be generating an error (when a function returns a dict(), web2py looks for an associated view to execute). Instead, you can just return nothing.
 
2. To be safe, I'll sanitize the expected integers like so:

    def add_item():
         # get json data as 'data' ...
         item_id = int(data['test']['item_id'])
         other_data = int(data['test']['some_detail'])
   
         # Insert that item_id and other_data into db...
   
    But if I expected a string, how would I sanitize that string before using it to do something with the database? Is there a safe practice for this type of approach of getting data from json?

Anthony

unread,
May 7, 2013, 11:45:44 AM5/7/13
to web...@googlegroups.com
If you use the browser tools to inspect the request/response, what do you see? Do you get a 200 status?

brac...@gmail.com

unread,
May 7, 2013, 1:53:57 PM5/7/13
to web...@googlegroups.com
I think something odd is going on. The Failed message never appears if I set breakpoints and step through the javascript in firebug. When I do this, I can see that the eventual post request has a status 200, but no success message is ever alerted.

If I remove the breakpoints and let the program run without interruption, then I see the post request, but the status column is left blank. I'd see the Failed alert pop up in this case.

Yet, in both cases, I see the my print statement being executed in the controller.

brac...@gmail.com

unread,
May 7, 2013, 3:00:57 PM5/7/13
to web...@googlegroups.com
I thought maybe this was an asynchronous problem or something similar, so I modified the util.js to do this:

function do Post(callback, data) {
    $
.post(callback, data).then(doSuccess, doFail);


   
function doSuccess(data) { alert('Success!'); }
   
function doFail(data) { alert('Failed!'); }
}

But it didn't solve the problem.

brac...@gmail.com

unread,
May 7, 2013, 3:01:54 PM5/7/13
to web...@googlegroups.com
Sorry, I had a typo in the last email: I meant to write "doPost()" and not "do Post()"
Reply all
Reply to author
Forward
0 new messages