Передача смешанной формы через ajax + iframe
версия для печатиОб этом давно и много написано. Причиной появления этой статьи стал тот печальный факт, что когда мне понадобилось решение, были потеряны часы на поиск и разбор неработающих скриптов и корявых библиотек. Видимо, мне так "свезло", раз не смог решить проблему быстро. Суть остается прежней: нужно передать с формы файл и данные без перегрузки страницы, подобно ajax-запросу. Используем jQuery и iframe.
Собственно почему jQuery/ajax, а не чистый javascript? Потому что так пример получится проще и скорее всего его практическое применение будет на сайтах, уже использующих библиотеку jQuery. Почему iframe? Это "дедовский" способ, работаюший даже в старых браузерах. Если нужно решение только под HTML5, тогда читайте про объект formData и XMLHttpRequest Level 2, с ними жизнь стала проще :)
Весь пример в архиве. Частичный код с пояснениями ниже.
<form id='formMessage' method='POST' target='uptarget' enctype='multipart/form-data' action='script.php'>
<input type='text' name='textField' value='some text'/><br>
<input type='file' name='attachment'><br>
<input type='submit' value='Отправить'>
</form>
<iframe name="uptarget" id="upframe" style="width:0px; height:0px; position:absolute; top:-9999px;"></iframe>
<div id='postRslt'></div>
Обычная форма со всеми нужными атрибутами. Важным является атрибут target, содержащий имя фрейма, куда будет отправлен ответ сервера после передачи с формы. Если не указывать этот приемник, тогда ответ сервера перепишет текущую страницу. Т.е. без правильного target получим поведение браузера, аналогичное обыкновенной отправке с формы. Только при этом от сервера не будет указания редиректа, т.к. он по замыслу должен вернуть только инфу об успешной/неудачной обработке данных. Фигня короче получится..
Тег iframe позволяет загрузить в себя отдельный документ, хотя при этом сам располагается с теле текущего документа. Используем его, чтобы принять нужный ответ сервера. А чтобы не палить его юзеру, задаем минимальные размеры фрейма и смещаем его за пределы окна. Прячем именно смещением, т.к. использование css-свойства " visibility:hidden " не помогает в FF и Opera, все равно остается маленький квадратик.
Все это хорошо работает, данные отправляются, страница не перегружается и скриты вообще не нужны. А вот чтобы как-то ненавязчиво сообщить юзеру о результате отправки, используем jQuery и свою фантазию =)
$(document).ready(function() {
//Вешаем обработчик на событие "Форма отправлена"
$('#formMessage').submit(function() {
//Обработчик события "Документ загружен"
$('#upframe').load(function() {
//Вытаскиваем из фрейма ответ сервера
var rslt = $(this).contents().find('body').html();
//Выдаем этот ответ, как результат загрузки с формы
$('#postRslt').html(rslt);
});
});
});
Добавить к комментариям нечего. Лучше расскажу про другой вариант. Фрейм можно создавать и удалять динамически. Не знаю, на сколько это удобно и нужно, просто можно. Из html убираем iframe, а в скрипте пишем:
$(document).ready(function() {
//глобальная переменная, чтоб несколько отправок не плодили фреймы
var iframe;
//Вешаем обработчик на событие "Форма отправлена"
$('#formMessage').submit(function() {
//создаем фрейм только на время отправки данных с формы
if (iframe
== undefined) {
iframe = $('<iframe name="uptarget" id="upframe" style="width:0px; height:0px; position:absolute; top:-9999px;"></iframe>');
}
$('#formMessage').append(iframe);
//это необязательно, если параметр формы уже задан
$('#formMessage').attr('target', 'uptarget');
//Обработчик события "Документ загружен"
$('#upframe').load(function() {
//Вытаскиваем из фрейма ответ сервера
var rslt = $(this).contents().find('body').html();
//Выдаем этот ответ, как результат загрузки с формы
$('#postRslt').html(rslt);
//Удаляем фрейм.. и это приводит в багу в Opera
iframe.remove();
});
});
});
При такой реализации получается баг в Opera 12. Удаление фрейма как-то обнуляет значение переменной rslt и юзер не увидит ответ. Не знаю, почему так. В FF и Chome все отлично работает.
Пару слов о серверном скрипте, хотя там почти ничего интересного.
header('Content-type: text/html; charset=utf-8');
//Валидация и сохранение файла
//...
echo 'Получен файл:';
var_dump($_FILES);
//Валидация данных и запись их куда-нибудь
//...
echo 'Получены данные:';
var_dump($_POST);
Текст скрипта сохраняем в кодировке UTF-8 без BOM для того, чтобы крякозябры не получить в ответе. Обязательно без BOM, иначе наступите на те же грабли, что и я. Или вообще сохраните его в ANSI и поменяйте в отправляемом заголовке кодировку на windows-1251 :-)
Справедливости ради нужно заметить, что использования ajax здесь вообще нет, назначенный обработчик load(), и тот работает после наступления события. Реальная загрузка проводится только по html-описанию. Просто поведение страницы похоже на ajax-запрос, отсюда и название. Эдакий маркетинговый ход статьи :)
[1oo%, EoF]Понравилась статья? Расскажите о ней друзьям: