= Ajax submiting and processing form errors with newforms and prototype =
== The task ==
{{{
#!html
- Show a form;
- Submit the form and show validation errors;
- Handle both js enabled and js disabled (ajax and standard form submiting).
}}}
I want to submit only the form and get validation errors from django newforms without submiting the whole page. Django Newforms library is really exciting and easy to use. Django is also great that doesn't restrict me to use any specific ajax/js library so I can use whatever I want in this case ''prototype''.
So I'm using
{{{
#!html
- django.newforms
- django.utils.simplejson which converts python data into JSON data so I can exchange it with the browser.
- And I'm using the great prototype.js library that makes javascript and ajax quite easy.
}}}
== The Form ==
The form is a simple contact form with all four fields required. Just to have something to validate. :)
{{{
#!python
from django import newforms as forms
from django.newforms.widgets import *
# A simple contact form with four fields.
class ContactForm(forms.Form):
name = forms.CharField()
email = forms.EmailField()
topic = forms.CharField()
message = forms.CharField(widget=Textarea())
}}}
== The View ==
The view returns either JSON with the errors from the form or a whole page if javascript is disabled in the browser.
I have a hidden input element in the form. I set it to None just before sending the form with javascript so the view knows what should it return, the whole page or just the errors with JSON.
The rest is just a generic newforms code. I check if the form is valid and redirect the user if it is or return the errors if it's not. When the form is valid and using AJAX I use a special field {'OK': 'java script for the browser to execute'}. The client-side javascript "knows" that it should run the javascript when it encounters 'OK'.
{{{
#!python
def contactview(request):
if request.method == 'POST':
theform = ContactForm(request.POST)
# if "js" got here together with the form it means that the
# browser doesn't have javascript so handle the form without js
js = request.POST.get('js', None)
if theform.is_valid():
if not js:
# simplejson makes a json format so we can do an
# eval() and run the javascript the view returns
jsaction = 'window.location.pathname="/"'
data = simplejson.dumps({'OK':jsaction})
else:
return HttpResponseRedirect('/')
else:
if not js:
data = simplejson.dumps(theform.errors)
else:
return render_to_response('contactform.html', {'form': theform})
return HttpResponse(data, mimetype="text/javascript")
else:
# show a blank form
return render_to_response('contactform.html', {'form': ContactForm()})
}}}
== The Javascript ==
{{{
#!text/html
}}}
== The Template ==
The template for the form has a span element with id="for_fieldname" where the javascript puts the errors and {{ forms.fieldname.errors }} where django puts the errors if javascript is disabled.
{{{
#!text/html
Contact form
}}}