Reputation: 9609
I'm trying to submit a form using web2py's ajax
function as explained in the book, but using FORM
instead of SQLFORM
since I don't want the data to be stored in a database.
ajax_test.html
{{extend "layout.html"}}
<h2>Form</h2>
{{=form}}
<script>
jQuery("#myform").submit(function() {
ajax("{{=URL('ajax_test')}}",
["mytext"], "output");
return false;
});
</script>
<h2>Output</h2>
<div id="output"></div>
Controller inside default.py:
def ajax_test():
form = FORM(
INPUT(_type="text", _name="mytext", _id="mytext",
requires=IS_NOT_EMPTY()),
INPUT(_type="submit"),
_id="myform"
)
if request.ajax:
if form.accepts(request.vars, session):
return DIV("Form submitted.")
elif form.errors:
return TABLE(*[TR(k, v) for k, v in form.errors.items()])
else:
return DIV("Couldn't check form.")
return dict(form=form)
When the form is submitted (request.ajax == True
), both form.accepts
and form.errors
return False
. Even though I access user's input via request.vars.mytext
, then I would need to validate it on my own instead of using web2py's capabilities.
What am I missing?
Upvotes: 1
Views: 908
Reputation: 25536
When you pass the session
object to form.accepts()
, it will automatically implement cross-site request forgery protection by adding a hidden _formkey
field to the form. When the form is submitted, the value of this hidden field is compared with the value stored in the session, and the form is not accepted if the match fails.
There are two problems with your code. First, you only call form.accepts
when there is an Ajax request, so the _formkey
does not get generated and included in the original form. To correct that, try the following:
form.process()
if request.ajax:
if form.accepted:
form.process()
is just a shortcut for form.accepts(request, session)
. Above, it is called even for the initial non-Ajax call when the form is created. This will generate the _formkey
value and store it in the session.
Second, your Javascript code does not submit the whole form but only the mytext
field, so the hidden _formkey
value will not be posted back to the server. As a result, the form is not accepted (web2py does not display an error in this case, as such a failure would typically be the result of foul play).
I'm not sure it is documented, but the second argument to the ajax()
function can instead be a jQuery selector, which will result in all form elements inside the selected element being serialized and submitted. So, try:
ajax('{{=URL('ajax_test')}}', '#myform', 'output');
The #myform
selector will result in the entire form being serialized, including the hidden fields included in the form
object.
Upvotes: 3