AJAX-валидация форм

Краткая заметка о том как валидировать формы не перезагружая страницу в браузере.
Я делал всё на базисе слайдов с конференции Oscon - AJAX-формам там посвящены кадры с 67 по 84.
Слайды можно смотреть тут [toys.jacobian.org].

Итак, что я хотел получить. Я хотел получить простой способ включения AJAX-валидации для форм с использованием логики валидации, уже реализованной ранее для проверки данных на стороне сервера.

Для этого я повесил на форму обработчик нажатия кнопки отправки.


<form method="post" onsubmit="return ajaxFormTest(this)">

<form method=”post” onsubmit=”return ajaxFormTest(this)”>


Он делает следующее, собирает значения полей формы в массив и отправляет его POST-запросом в тот же view, что занимается серверной валидацией. Для того чтобы view мог отличать AJAX-запросы от обычных, я добавляю параметр _ajax в данные AJAX-запроса.

Далее, view в любом случае создаёт объект формы по предоставленным данным, а затем, если это AJAX-запрос, то выполнение view прерывается и в бразуер возращается список ошибок, возникших в процессе валидации. Он моожет быть и пустым, что означет, что все данные корректны.Список передаётся в сериализованном виде (в JSON формате).

Теперь посмотрим, что происходит в браузере, когда он получает этот список. А происходит следующее: если ошибки есть, мы их отображаем, если нету, то засылаем форму на сервер, теперь уже “по настоящему”.

Ну, а на последок немного кода.

Так выглядит типичный view


@render_to('bar.html')
def registration(request):
if 'POST' == request.method:
form = BarForm(request.POST)
else:
form = BarForm()
if '_ajax' in request.POST:
return ajaxform(form)
if form.is_valid():
user = form.save()
return HttpResponseRedirect('/')
return {
'form':form}

@render_to(‘bar.html’)
def registration(request):
if ‘POST’ == request.method:
form = BarForm(request.POST)
else:
form = BarForm()
if ‘_ajax’ in request.POST:
return ajaxform(form)
if form.is_valid():
user = form.save()
return HttpResponseRedirect(‘/’)
return {
‘form’:form}


Это функция ajaxform, которая сериализует данные для передачи в браузер:


def ajaxform(form):
return JsonResponse({'errors': form.errors, 'valid': not form.errors})

def ajaxform(form):
return JsonResponse({‘errors’: form.errors, ‘valid’: not form.errors})


Это класс JsonResponse:


class JsonResponse(HttpResponse):
def __init__(self, data):
json_data = simplejson.dumps(data)
super(JsonResponse, self).__init__(
content=json_data, mimetype='application/json')

class JsonResponse(HttpResponse):
def __init__(self, data):
json_data = simplejson.dumps(data)
super(JsonResponse, self).__init__(
content=json_data, mimetype=’application/json’)


Это javascript-код для работы на стороне браузера:


<script type="text/javascript" src="/pub/jquery/jquery.js"></script>
<script type="text/javascript" src="/pub/jquery/jquery.form.js"></script>
<script type="text/javascript">

function ajaxFormTest(form) {
var postData = $(form).formToArray()
postData[postData.length] = {'name': '_ajax', 'value': true}
var url = $(form).attr('action') ? form.action : location
$.post(url, postData, function(data) {
var json = eval('(' + data + ')')
showErrors(form, json.errors)
if (json.valid) {
form.submit()
}
})
return false
}

function getInputErrorList(form, input_name) {
var input = $('[@name="' + input_name + '"]', form)[0]
var prevUL = $(input).parent().prev()
if (prevUL && prevUL.attr('class') == 'errorlist') {
return prevUL
}
var errorList = $('<ul class="errorlist"></ul>')
$(input).parent().before(errorList)
return errorList
}

function showErrors(form, errors) {
$('.errorlist', form).empty()
for (var field in errors) {
var errorList = getInputErrorList(form, field)
$.each(errors[field], function(i, error) {
$(errorList).append('<li>' + error + '</li>')
})
}
}
</script>

<script type=”text/javascript” src=”/pub/jquery/jquery.js”></script>
<script type=”text/javascript” src=”/pub/jquery/jquery.form.js”></script>
<script type=”text/javascript”>

function ajaxFormTest(form) {
var postData = $(form).formToArray()
postData[postData.length] = {‘name’: ‘_ajax’, ‘value’: true}
var url = $(form).attr(‘action’) ? form.action : location
$.post(url, postData, function(data) {
var json = eval(‘(‘ + data + ‘)’)
showErrors(form, json.errors)
if (json.valid) {
form.submit()
}
})
return false
}

function getInputErrorList(form, input_name) {
var input = $(‘[@name=”’ + input_name + ‘”]’, form)[0]
var prevUL = $(input).parent().prev()
if (prevUL && prevUL.attr(‘class’) == ‘errorlist’) {
return prevUL
}
var errorList = $(‘<ul class=”errorlist”></ul>’)
$(input).parent().before(errorList)
return errorList
}

function showErrors(form, errors) {
$(‘.errorlist’, form).empty()
for (var field in errors) {
var errorList = getInputErrorList(form, field)
$.each(errors[field], function(i, error) {
$(errorList).append(‘<li>’ + error + ‘</li>’)
})
}
}
</script>


Дополнительные сведения по работе JS-кода можно почерпнуть из слайдов, о которых я сказал в начале этой статьи. Я его изменил на свой вкус, но основные моменты такие же.
Add post to:   Google Slashdot Yahoo Digg Technorati Delicious Bobrdobr.ru Newsland.ru Smi2.ru Rumarkz.ru Vaau.ru Memori.ru Rucity.com Moemesto.ru News2.ru Mister-Wong.ru Yandex.ru Myscoop.ru 100zakladok.ru
Make comment

Comments

No comments for this post
comment submission form

Required. 30 chars of fewer.

Required.

captcha image Please, enter symbols, which you see on the image