Завантаження даних і файлів в одній формі за допомогою Ajax?


384

Я використовую 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 який хоч? той, з серіалізацією, здається, працює лише для даних, а інший, здається, працює лише для файлів?
День

Судячи з цієї сторінки MDN , всі дані форми потрібно надсилати під час використанняFormData
lanzz

1
@lanzz Ви праві, це працює так, як я вважав, що я повинен використовувати неправильний ідентифікатор форми, ви можете завантажувати і файли, і дані через одну форму за допомогою ajax.
День

Це, здається, не спрацьовує, коли вводиться файл з декількома виборами. Він завантажує лише перший файл.
Самі Аль-Субхі

Відповіді:


458

Проблема, яку я мав, була з використанням неправильного ідентифікатора 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.
Xavier Guzman

34
$(this)[0]це лише псевдонім this, тому new FormData(this)має бути достатнім.
r3wt

9
Здається, неможливо оглянути об’єкт FormData, дивіться це запитання (для тих, хто стикається з такою ж безглуздістю, як і я, тому що Об'єкт завжди був порожній).
Лаура

28
Для майбутніх читачів: contentType та processData-декларації важливі. Дивіться цю відповідь для отримання додаткової інформації.
AaronSieb

5
async: falseчи не здається для цього потрібно , щоб працювати і викликає блокування мобільних (однопотоковий) браузерів
Джеремі Daalder

33

інший варіант - використовувати 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, я в кінцевому підсумку скористався цією
мірою,

Ця відповідь повинна міститись у нитці, оскільки інші відповіді відзначають "старіші браузери не працюють" або "хакер-рамка може бути використана", але ніколи їх не адресує. Приємний фрагмент коду, також показано, як правильно використовувати onload +1
mschr

18

У мене був такий самий випуск у ASP.Net MVC з HttpPostedFilebase, і замість того, щоб використовувати форму на Submit, мені потрібно було натиснути кнопку, натиснувши там, де мені потрібно зробити якісь речі, а потім, якщо все гаразд, надіслати форму.

$(".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; }
}


У моєму випадку мені довелося скористатися:contentType : "application/octet-stream"
Крістоф Руссі,

Дякую друже! Ви зекономили багато часу.
Доступ заборонено

Це працює з Django, приємно!
csandreas1

Дякую, друже! Нижче наведені 2 рядки. var form = $ ("# форма"); var formData = новий FormData (форма [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взагалі не згадується.
Квентін

Як я вже згадував раніше, я спробував декілька різних відповідей, але вони не спрацювали. На консолі JS була показана помилка Ajax, що вказує на помилку кодування. Пізніше я слідував за цим підручником, який нарешті змусив свій код працювати, і я розмістив його тут. Можливо, enctypeполе чомусь не висвітлено в документації. Я не перевірив вихідний код jQuery, тому не можу сказати з упевненістю.
Адітія Упадхя

"Можливо, поле ентетипу чомусь не висвітлено в документації." - Ця причина полягає в тому, що jQuery з цим нічого не робить, тому це нісенітниця.
Квентін

Можливо, ви могли б зв’язатися з Мкьонгом і натомість поговорити з ним. Я знову перевірив свій код, видаливши 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);
});

У своєму Методі публікації дій передайте параметр як HttpPostedFileBase UploadFile та переконайтесь, що вхід у файл такий же, як зазначено у вашому параметрі Методу дії. Він також повинен працювати з формою AJAX Begin.

Пам’ятайте тут, що ваша форма AJAX BEGIN не працюватиме тут, оскільки ви здійснюєте свою поштову розмову, визначену в зазначеному вище коді, і ви можете посилатися на свій метод у коді відповідно до вимоги

Я знаю, що відповідаю пізно, але саме це працювало на мене


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 до файлу маршруту в 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.