Jonny
Jonny

Reputation: 872

web2py - ajax call returns 404 or fails to process parameters

I have a function defined in my controller:

def get_config_values():
    path = unescape(request.vars['path'])
    config = get_config_as_dict(path)
    return dict(config)

And in my view I use jQuery $.ajax() to call it in the view:

$.ajax({
      url: "{{=URL('get_config_values.json')}}", 
      contentType: "application/json; charset=utf-8", 
      data: {
         path: page_path,
      },
      error: function(x, y, z) {
         show_error(x.responseText, y, z);
         hide_drawer();
      },
      success: function(data) {
         $('#drawer_content').html(data);
      },
      type: 'POST',
   });

And put simply I cannot get this to work.

Web2py seems to behave quite strangely here - to get the POST working in the first place I had to explictly set contentType: "application/json" otherwise I'd see a 404 there as well, despite the data:'json' already there.

Has anyone else seen and worked around this behaviour? I don't care if the call is GET or POST, I just want it to work!

Upvotes: 0

Views: 565

Answers (1)

Anthony
Anthony

Reputation: 25536

There are a few problems. First, when a web2py action returns a dictionary, web2py looks for an associated view to execute (based on the path of the action as well as the extension). In this case, it will look for a view with the path /views/controller_name/get_config_values.json. If it doesn't find that view, it may attempt to use the generic.json view, but only if you have explicitly enabled the generic view via response.generic_patterns (in the scaffolding app, all generic views are enabled by default, but only for local requests). Otherwise, you will get a 404 error (if you inspect the body of the error message in the browser developer tools, you should see a message about an invalid view).

Second, to post JSON via jQuery, you have to convert your Javascript object to a JSON string:

data: JSON.stringify(
    {
        path: page_path
    }
),

With the above, you should now have the value of page_path in request.vars.path on the server.

Finally, if you request a .json URL from web2py, it will set the Content-Type response header to "application/json". However, based on your Javascript code, it appears you want to return HTML (given that you are placing the results into a div on the page). So, you should probably not use the .json extension in the request (you can also explicitly tell jQuery that the response is HTML by setting dataType: 'html').

So, try the following:

$.ajax({
  url: "{{=URL('get_config_values')}}", 
  contentType: "application/json; charset=utf-8", 
  data: JSON.stringify({
     path: page_path,
  }),
  error: function(x, y, z) {
     show_error(x.responseText, y, z);
     hide_drawer();
  },
  success: function(data) {
     $('#drawer_content').html(data);
  },
  type: 'POST',
});

Then either create a get_config_values.html view that generates the desired HTML from the returned dictionary, or otherwise have the get_config_values function directly return an HTML string.

If you instead do want to return JSON to the browser, then you will need to change your success callback to process the JSON before attempting to place it in a div.

Upvotes: 2

Related Questions