Как отправить объекты FormData с помощью Ajax-запросов в jQuery?
Стандарт XMLHttpRequest Level 2 (все еще рабочий проект) определяет интерфейс FormData
. Этот интерфейс позволяет добавлять объекты File
к XHR-запросам (Ajax-запросы).
Btw, это новая функция - в прошлом использовался "скрытый-iframe-трюк" (читал об этом в мой другой вопрос).
Вот как это работает (пример):
var xhr = new XMLHttpRequest(),
fd = new FormData();
fd.append( 'file', input.files[0] );
xhr.open( 'POST', 'http://example.com/script.php', true );
xhr.onreadystatechange = handler;
xhr.send( fd );
где input
- это поле <input type="file">
, а handler
- обработчик успеха для запроса Ajax.
Это прекрасно работает во всех браузерах (опять же, кроме IE).
Теперь я хотел бы, чтобы эта функциональность работала с jQuery. Я пробовал это:
var fd = new FormData();
fd.append( 'file', input.files[0] );
$.post( 'http://example.com/script.php', fd, handler );
К сожалению, это не сработает (вызывается ошибка "Незаконный вызов" - снимок экрана здесь). Я предполагаю, что jQuery ожидает простой объект "ключ-значение", представляющий имена полей/значений формы, и экземпляр FormData
, который я передаю, по-видимому, несовместим.
Теперь, поскольку можно передать экземпляр FormData
в xhr.send()
, я надеюсь, что также возможно заставить его работать с jQuery.
Update:
Я создал "билет функции" в jQuery Bug Tracker. Здесь: http://bugs.jquery.com/ticket/9995
Мне предложили использовать "предварительный фильтр Ajax"...
Update:
Во-первых, позвольте мне дать демонстрацию, демонстрирующую, какого поведения я бы хотел достичь.
HTML:
<form>
<input type="file" id="file" name="file">
<input type="submit">
</form>
JavaScript:
$( 'form' ).submit(function ( e ) {
var data, xhr;
data = new FormData();
data.append( 'file', $( '#file' )[0].files[0] );
xhr = new XMLHttpRequest();
xhr.open( 'POST', 'http://hacheck.tel.fer.hr/xml.pl', true );
xhr.onreadystatechange = function ( response ) {};
xhr.send( data );
e.preventDefault();
});
Приведенный выше код приводит к этому HTTP-запросу:
Это то, что мне нужно. Я хочу, чтобы этот тип контента "multipart/form-data" был
Предлагаемое решение будет таким:
$( 'form' ).submit(function ( e ) {
var data;
data = new FormData();
data.append( 'file', $( '#file' )[0].files[0] );
$.ajax({
url: 'http://hacheck.tel.fer.hr/xml.pl',
data: data,
processData: false,
type: 'POST',
success: function ( data ) {
alert( data );
}
});
e.preventDefault();
});
Однако это приводит к:
Как вы можете видеть, тип содержимого неверен...
Ответы
Ответ 1
Я считаю, что вы могли бы сделать это вот так:
var fd = new FormData();
fd.append( 'file', input.files[0] );
$.ajax({
url: 'http://example.com/script.php',
data: fd,
processData: false,
contentType: false,
type: 'POST',
success: function(data){
alert(data);
}
});
Настройка processData
на false позволяет запретить jQuery автоматически преобразовывать данные в строку запроса. Подробнее см. документы.
Установка параметра contentType
в значение false является обязательным, поскольку в противном случае jQuery установит его неверно.
Ответ 2
Есть еще несколько доступных для вас методов. Начните с установки свойства contentType в параметрах ajax.
Основываясь на примере pradeek:
$('form').submit(function (e) {
var data;
data = new FormData();
data.append('file', $('#file')[0].files[0]);
$.ajax({
url: 'http://hacheck.tel.fer.hr/xml.pl',
data: data,
processData: false,
type: 'POST',
// This will override the content type header,
// regardless of whether content is actually sent.
// Defaults to 'application/x-www-form-urlencoded'
contentType: 'multipart/form-data',
//Before 1.5.1 you had to do this:
beforeSend: function (x) {
if (x && x.overrideMimeType) {
x.overrideMimeType("multipart/form-data");
}
},
// Now you should be able to do this:
mimeType: 'multipart/form-data', //Property added in 1.5.1
success: function (data) {
alert(data);
}
});
e.preventDefault();
});
В некоторых случаях, когда jQuery ajax делает непредвиденные события, событие beforeSend
- отличное место для этого. Некоторое время люди использовали beforeSend
для переопределения mimeType до того, как он был добавлен в jQuery в 1.5.1. Вы должны иметь возможность изменять что угодно на объекте jqXHR в событии перед отправкой.
Ответ 3
Вы можете отправить объект FormData в ajax-запрос, используя следующий код,
$("form#formElement").submit(function(){
var formData = new FormData($(this)[0]);
});
Это очень похоже на принятый ответ, но на фактический ответ на вопрос. Это автоматически представит элементы формы в FormData, и вам не нужно вручную добавлять данные в переменную FormData.
Метод ajax выглядит следующим образом:
$("form#formElement").submit(function(){
var formData = new FormData($(this)[0]);
//append some non-form data also
formData.append('other_data',$("#someInputData").val());
$.ajax({
type: "POST",
url: postDataUrl,
data: formData,
processData: false,
contentType: false,
dataType: "json",
success: function(data, textStatus, jqXHR) {
//process data
},
error: function(data, textStatus, jqXHR) {
//process error msg
},
});
Вы также можете вручную передать элемент формы внутри объекта FormData в качестве параметра, подобного этому
var formElem = $("#formId");
var formdata = new FormData(form[0]);
Надеюсь, поможет. ;)
Ответ 4
Вы можете использовать событие $.ajax beforeSend
для управления заголовком.
...
beforeSend: function(xhr) {
xhr.setRequestHeader('Content-Type', 'multipart/form-data');
}
...
Дополнительную информацию см. на этой ссылке: http://msdn.microsoft.com/en-us/library/ms536752(v=vs.85).aspx
Ответ 5
Я думаю, что вы не можете сделать это в ajax для поддержки всех браузеров, я могу сказать, что хорошо проверить этот плагин для ajax uploader, чтобы посмотреть, как они это сделали http://valums.com/ajax-upload/
Ответ 6
Я делаю это так, и это работает для меня, я надеюсь, что это поможет:)
<div id="data">
<form>
<input type="file" name="userfile" id="userfile" size="20" />
<br /><br />
<input type="button" id="upload" value="upload" />
</form>
</div>
<script>
$(document).ready(function(){
$('#upload').click(function(){
console.log('upload button clicked!')
var fd = new FormData();
fd.append( 'userfile', $('#userfile')[0].files[0]);
$.ajax({
url: 'upload/do_upload',
data: fd,
processData: false,
contentType: false,
type: 'POST',
success: function(data){
console.log('upload success!')
$('#data').empty();
$('#data').append(data);
}
});
});
});
</script>
Ответ 7
Если вы хотите отправлять файлы с использованием ajax, используйте "jquery.form.js"
Это легко передает элементы формы.
Образцы
http://jquery.malsup.com/form/#ajaxSubmit
приблизительный вид:
<form id='AddPhotoForm' method='post' action='../photo/admin_save_photo.php' enctype='multipart/form-data'>
<script type="text/javascript">
function showResponseAfterAddPhoto(responseText, statusText)
{
information= responseText;
callAjaxtolist();
$("#AddPhotoForm").resetForm();
$("#photo_msg").html('<div class="album_msg">Photo uploaded Successfully...</div>');
};
$(document).ready(function(){
$('.add_new_photo_div').live('click',function(){
var options = {success:showResponseAfterAddPhoto};
$("#AddPhotoForm").ajaxSubmit(options);
});
});
</script>
Ответ 8
JavaScript:
function submitForm() {
var data1 = new FormData($('input[name^="file"]'));
$.each($('input[name^="file"]')[0].files, function(i, file) {
data1.append(i, file);
});
$.ajax({
url: "<?php echo base_url() ?>employee/dashboard2/test2",
type: "POST",
data: data1,
enctype: 'multipart/form-data',
processData: false, // tell jQuery not to process the data
contentType: false // tell jQuery not to set contentType
}).done(function(data) {
console.log("PHP Output:");
console.log( data );
});
return false;
}
PHP:
public function upload_file(){
foreach ($_FILES as $key ) {
$name =time().$key['name'];
$path='upload/'.$name;
@move_uploaded_file($key['tmp_name'],$path);
}
Ответ 9
Вместо fd.append( 'userfile', $('#userfile')[0].files[0]);
Использование - fd.append( 'file', $('#userfile')[0].files[0]);
Ответ 10
Лучшая документация и пример, который я нашел, были здесь https://developer.mozilla.org/en-US/docs/Web/Guide/Using_FormData_Objects