Загрузка данных и файлов в одной форме с помощью Ajax?


386

Я использую jQuery и Ajax для своих форм для отправки данных и файлов, но я не уверен, как отправить данные и файлы в одной форме?

В настоящее время я делаю почти одно и то же с обоими методами, но способ, которым данные собираются в массив, отличается, данные используют, .serialize();но файлы используют= new FormData($(this)[0]);

Можно ли объединить оба метода, чтобы можно было загружать файлы и данные в одной форме через Ajax?

Данные jQuery, Ajax и HTML

$("form#data").submit(function(){

    var formData = $(this).serialize();

    $.ajax({
        url: window.location.pathname,
        type: 'POST',
        data: formData,
        async: false,
        success: function (data) {
            alert(data)
        },
        cache: false,
        contentType: false,
        processData: false
    });

    return false;
});

<form id="data" method="post">
    <input type="text" name="first" value="Bob" />
    <input type="text" name="middle" value="James" />
    <input type="text" name="last" value="Smith" />
    <button>Submit</button>
</form>

Файлы jQuery, Ajax и html

$("form#files").submit(function(){

    var formData = new FormData($(this)[0]);

    $.ajax({
        url: window.location.pathname,
        type: 'POST',
        data: formData,
        async: false,
        success: function (data) {
            alert(data)
        },
        cache: false,
        contentType: false,
        processData: false
    });

    return false;
});

<form id="files" method="post" enctype="multipart/form-data">
    <input name="image" type="file" />
    <button>Submit</button>
</form>

Как я могу объединить вышеперечисленное, чтобы я мог отправлять данные и файлы в одной форме через Ajax?

Моя цель - иметь возможность отправить всю эту форму в одном сообщении с помощью Ajax, возможно ли это?

<form id="datafiles" method="post" enctype="multipart/form-data">
    <input type="text" name="first" value="Bob" />
    <input type="text" name="middle" value="James" />
    <input type="text" name="last" value="Smith" />
    <input name="image" type="file" />
    <button>Submit</button>
</form>

2
FormDataПодход должен работать нормально с формами , которые содержат все , что вы хотите, а не только поля закачивать файл; это не широко поддерживается, хотя.
Lanzz

@lanzz, который хотя? один с serialize, кажется, работает только для данных, а другой, кажется, работает только для файлов?
Дан

Судя по этой странице MDN , все данные формы должны быть представлены при использованииFormData
lanzz

1
@lanzz вы правы, все работает так, как мне показалось, я использовал неправильный идентификатор формы, вы можете загружать как файлы, так и данные через одну форму с помощью ajax.
Dan

Это, кажется, не работает, когда есть многократный выбор файла. Он загружает только первый файл.
Сами Аль-Субхи

Ответы:


459

У меня была проблема с неправильным идентификатором jQuery.

Вы можете загружать данные и файлы с помощью одной формы, используя ajax .

PHP + HTML

<?php

print_r($_POST);
print_r($_FILES);
?>

<form id="data" method="post" enctype="multipart/form-data">
    <input type="text" name="first" value="Bob" />
    <input type="text" name="middle" value="James" />
    <input type="text" name="last" value="Smith" />
    <input name="image" type="file" />
    <button>Submit</button>
</form>

JQuery + Ajax

$("form#data").submit(function(e) {
    e.preventDefault();    
    var formData = new FormData(this);

    $.ajax({
        url: window.location.pathname,
        type: 'POST',
        data: formData,
        success: function (data) {
            alert(data)
        },
        cache: false,
        contentType: false,
        processData: false
    });
});

Укороченная версия

$("form#data").submit(function(e) {
    e.preventDefault();
    var formData = new FormData(this);    

    $.post($(this).attr("action"), formData, function(data) {
        alert(data);
    });
});

17
в версиях IE <10 это решение не будет работать, так как FormData - это объект HTML5, отсутствующий в IE 8 или 9.
Ксавье Гузман,

34
$(this)[0]это просто псевдоним this, поэтому new FormData(this)должно быть достаточно.
r3wt

9
Кажется, что невозможно проверить Объект FormData, посмотрите этот вопрос (для тех, кто сталкивался с той же невежественностью, что и я, потому что Объект всегда был пустым).
Лора

28
Для будущих читателей: объявления contentType и processData важны. Смотрите этот ответ для получения дополнительной информации.
AaronSieb

5
async: falseКажется, что это не требуется для работы и вызывает блокировку в мобильных (однопоточных) браузерах
Джереми Даалдер

34

Другой вариант - использовать iframe и установить для него цель формы.

Вы можете попробовать это (он использует jQuery):

function ajax_form($form, on_complete)
{
    var iframe;

    if (!$form.attr('target'))
    {
        //create a unique iframe for the form
        iframe = $("<iframe></iframe>").attr('name', 'ajax_form_' + Math.floor(Math.random() * 999999)).hide().appendTo($('body'));
        $form.attr('target', iframe.attr('name'));
    }

    if (on_complete)
    {
        iframe = iframe || $('iframe[name="' + $form.attr('target') + '"]');
        iframe.load(function ()
        {
            //get the server response
            var response = iframe.contents().find('body').text();
            on_complete(response);
        });
    }
}

он хорошо работает со всеми браузерами, вам не нужно сериализовать или подготавливать данные. один недостаток в том, что вы не можете следить за прогрессом.

также, по крайней мере для chrome, запрос будет отображаться не на вкладке "xhr" инструментов разработчика, а в разделе "doc"


1
На самом деле это не Ajax, все еще может быть полезным для людей с таким же вопросом.
Роуи

3
Я просто не могу поверить, почему этот ответ получил -2, в итоге я использовал его, так как мне требовалась поддержка устаревшего браузера
Sijav

Этот ответ должен быть в ветке, так как другие ответы отмечают, что «старые браузеры не работают» или «можно использовать iframe hack», но никогда не обращаются к ним. Хороший фрагмент кода, также показывающий, как правильно использовать onload +1
mschr

18

У меня была такая же проблема в ASP.Net MVC с HttpPostedFilebase, и вместо использования формы при отправке мне нужно было нажимать кнопку, когда мне нужно было что-то делать, а затем, если все в порядке, отправить форму, вот как я ее получил

$(".submitbtn").on("click", function(e) {

    var form = $("#Form");

    // you can't pass Jquery form it has to be javascript form object
    var formData = new FormData(form[0]);

    //if you only need to upload files then 
    //Grab the File upload control and append each file manually to FormData
    //var files = form.find("#fileupload")[0].files;

    //$.each(files, function() {
    //  var file = $(this);
    //  formData.append(file[0].name, file[0]);
    //});

    if ($(form).valid()) {
        $.ajax({
            type: "POST",
            url: $(form).prop("action"),
            //dataType: 'json', //not sure but works for me without this
            data: formData,
            contentType: false, //this is requireded please see answers above
            processData: false, //this is requireded please see answers above
            //cache: false, //not sure but works for me without this
            error   : ErrorHandler,
            success : successHandler
        });
    }
});

это будет правильно заполнять вашу модель MVC, пожалуйста, убедитесь, что в вашей модели свойство HttpPostedFileBase [] имеет то же имя, что и имя элемента управления вводом в html, т.е.

<input id="fileupload" type="file" name="UploadedFiles" multiple>

public class MyViewModel
{
    public HttpPostedFileBase[] UploadedFiles { get; set; }
}

1
Вы экономите время. :)
Сухайль Мумтаз Аван

В моем случае я должен был использовать:contentType : "application/octet-stream"
Кристоф Русси

Спасибо, приятель! Вы сэкономили много времени.
Доступ запрещен

Это работает с Джанго, хорошо!
csandreas1

Спасибо друг! Ниже 2 строки работали для меня. var form = $ ("# Form"); var formData = new FormData (form [0]);
Раджив Кумар

15

Или короче:

$("form#data").submit(function() {
    var formData = new FormData(this);
    $.post($(this).attr("action"), formData, function() {
        // success    
    });
    return false;
});

так с этим, как вы проверяете поле данных, используя тот же сценарий, то есть, если у вас есть текстовое поле и поле файла в вашей форме
Джордж

6

Для меня это не работает без enctype: 'multipart/form-data'поля в запросе Ajax. Я надеюсь, что это помогает кому-то, кто застрял в аналогичной проблеме.

Хотя по какой-то причине enctype атрибут Ajax уже был задан в атрибуте формы , он не идентифицировал автоматически enctypeбез явного объявления (jQuery 3.3.1).

// Tested, this works for me (jQuery 3.3.1)

fileUploadForm.submit(function (e) {   
    e.preventDefault();
    $.ajax({
            type: 'POST',
            url: $(this).attr('action'),
            enctype: 'multipart/form-data',
            data: new FormData(this),
            processData: false,
            contentType: false,
            success: function (data) {
                console.log('Thank God it worked!');
            }
        }
    );
});

// enctype field was set in the form but Ajax request didn't set it by default.

<form action="process/file-upload" enctype="multipart/form-data" method="post" >

     <input type="file" name="input-file" accept="text/plain" required> 
     ...
</form>

Как и другие упомянутые выше, пожалуйста , также обратить особое внимание на contentTypeи processDataполей.


1
«Для меня это не сработало без enctype: поля« multipart / form-data »в запросе Ajax». - Это не могло иметь никакого эффекта. Это свойство не распознается jQuery.ajax. Смотрите документацию, где enctypeвообще не упоминается.
Квентин,

Как я упоминал ранее, я пробовал несколько разных ответов, но они не работали. Ошибка Ajax с указанием ошибки кодирования была показана в консоли JS. Позже я последовал этому уроку, который, наконец, заставил мой код работать, и я разместил его здесь. Возможно, enctypeполе не указано в документации по причине. Я не проверял исходный код jQuery, поэтому не могу с уверенностью сказать.
Адитья Упадхья

«Возможно, поле enctype не указано в документации по причине». - Причина в том, что jQuery ничего с этим не делает, поэтому это чепуха.
Квентин

Возможно, вы могли бы связаться с Mkyong и поговорить с ним вместо этого. Я снова проверил свой код, удалив enctypeполе, и оно больше не загружает файлы (возвращается ошибка типа кодировки). Я не уверен, как это работает, так как я не проверял исходный код jQuery. Я разместил этот ответ с намерением помочь другим, кто застрял в аналогичной проблеме. Я не собираюсь отдавать предпочтение здесь ... Если у вас есть дополнительные вопросы / комментарии, давайте пообщаемся, а не комментируем.
Адитья Упадхья

1

Для меня следующий код работает

$(function () {
    debugger;
    document.getElementById("FormId").addEventListener("submit", function (e) {
        debugger;
        if (ValidDateFrom()) { // Check Validation 
            var form = e.target;
            if (form.getAttribute("enctype") === "multipart/form-data") {
                debugger;
                if (form.dataset.ajax) {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                    var xhr = new XMLHttpRequest();
                    xhr.open(form.method, form.action);
                    xhr.onreadystatechange = function (result) {
                        debugger;
                        if (xhr.readyState == 4 && xhr.status == 200) {
                            debugger;
                            var responseData = JSON.parse(xhr.responseText);
                            SuccessMethod(responseData); // Redirect to your Success method 
                        }
                    };
                    xhr.send(new FormData(form));
                }
            }
        }
    }, true);
});

В вашем методе Action Post передайте параметр как HttpPostedFileBase UploadFile и убедитесь, что входные данные вашего файла совпадают с указанными в параметре метода действия. Он также должен работать с формой AJAX Begin.

Помните здесь, что ваша AJAX BEGIN Form не будет работать здесь, так как вы делаете свой почтовый вызов, определенный в коде, упомянутом выше, и вы можете ссылаться на свой метод в коде в соответствии с Требованием

Я знаю, что отвечаю поздно, но это то, что сработало для меня


1

Простой, но более эффективный способ:
new FormData()сам по себе как контейнер (или сумка). Вы можете поместить все attr или файл в себя. Единственное, что вам нужно добавить, attribute, file, fileNameнапример:

let formData = new FormData()
formData.append('input', input.files[0], input.files[0].name)

и просто передать его в запросе AJAX. Например:

    let formData = new FormData()
    var d = $('#fileid')[0].files[0]

    formData.append('fileid', d);
    formData.append('inputname', value);

    $.ajax({
        url: '/yourroute',
        method: 'POST',
        contentType: false,
        processData: false,
        data: formData,
        success: function(res){
            console.log('successfully')
        },
        error: function(){
            console.log('error')
        }
    })

Вы можете добавить n файлов или данных с помощью FormData.

и если вы делаете запрос AJAX из файла Script.js в файл Route в Node.js, остерегайтесь использовать его
req.bodyдля доступа к данным (например, тексту)
req.filesдля доступа к файлу (например, к изображению, видео и т. д.)


-1

В моем случае мне нужно было сделать запрос POST, в котором информация была отправлена ​​через заголовок, а также файл, отправленный с использованием объекта FormData.

Я заставил это работать, используя комбинацию некоторых ответов здесь, так что в основном получилось, что в моем Ajax-запросе было пять строк:

 contentType: "application/octet-stream",
 enctype: 'multipart/form-data',
 contentType: false,
 processData: false,
 data: formData,

Где formData была переменная, созданная следующим образом:

 var file = document.getElementById('uploadedFile').files[0];
 var form = $('form')[0];
 var formData = new FormData(form);
 formData.append("File", file);

1
contentType: "application/octet-stream",Он активно вреден, и единственная причина, по которой он не вызывает проблем, заключается в том, что вы перезаписываете его двумя строками позже.
Квентин,

1
enctype: 'multipart/form-data',бессмысленно. jQuery.ajax не распознает этот параметр.
Квентин,

… Остальная часть вашего ответа не покрывает бит «данных» «данных и файлов» из заголовка вопроса.
Квентин,

-2
<form id="form" method="post" action="otherpage.php" enctype="multipart/form-data">
    <input type="text" name="first" value="Bob" />
    <input type="text" name="middle" value="James" />
    <input type="text" name="last" value="Smith" />
    <input name="image" type="file" />
    <button type='button' id='submit_btn'>Submit</button>
</form>

<script>
$(document).on("click", "#submit_btn", function (e) {
    //Prevent Instant Click  
    e.preventDefault();
    // Create an FormData object 
    var formData = $("#form").submit(function (e) {
        return;
    });
    //formData[0] contain form data only 
    // You can directly make object via using form id but it require all ajax operation inside $("form").submit(<!-- Ajax Here   -->)
    var formData = new FormData(formData[0]);
    $.ajax({
        url: $('#form').attr('action'),
        type: 'POST',
        data: formData,
        success: function (response) {
            console.log(response);
        },
        contentType: false,
        processData: false,
        cache: false
    });
    return false;
});
</script>

///// otherpage.php

<?php
    print_r($_FILES);
?>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.