Przesyłasz zarówno dane, jak i pliki w jednej formie za pomocą Ajax?


384

Używam jQuery i Ajax do formularzy do przesyłania danych i plików, ale nie jestem pewien, jak wysłać zarówno dane, jak i pliki w jednym formularzu?

Obecnie robię prawie to samo z obiema metodami, ale sposób, w jaki dane są gromadzone w tablicy, jest inny, dane używają, .serialize();ale pliki używają= new FormData($(this)[0]);

Czy można połączyć obie metody, aby móc przesyłać pliki i dane w jednej formie za pośrednictwem Ajax?

Dane jQuery, Ajax i 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>

Pliki jQuery, Ajax i 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>

Jak połączyć powyższe, aby móc wysyłać dane i pliki w jednej formie za pośrednictwem Ajax?

Moim celem jest, aby móc wysłać cały ten formularz w jednym poście z Ajax, czy to możliwe?

<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
FormDataPodejście powinno działać dobrze z form, które zawierają co chcesz, nie tylko pola Prześlij plik; nie jest to jednak powszechnie obsługiwane.
— lanzz

@lanzz które jednak? ten z serializacją wydaje się działać tylko dla danych, ale drugi wydaje się działać tylko dla plików?
— Dan

Sądząc po tej stronie MDN , wszystkie dane formularza należy przesłać podczas korzystaniaFormData
— lanzz

1
@lanzz masz rację, działa tak, jak myślałem, że powinienem używać niewłaściwego identyfikatora formularza, możesz przesyłać zarówno pliki, jak i dane za pośrednictwem jednego formularza za pomocą ajax.
— Dan

Wydaje się, że to nie działa, gdy istnieje plik z wielokrotnym wyborem pliku. Przesyła tylko pierwszy plik.
— Sami Al-Subhi,

Odpowiedzi:


458

Problem, który miałem, to użycie niewłaściwego identyfikatora jQuery.

Możesz przesyłać dane i pliki w jednym formularzu za pomocą 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
    });
});

Krótka wersja

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

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

17
w wersjach IE <10 to rozwiązanie nie będzie działać, ponieważ FormData jest obiektem HTML5, nieobecnym w IE 8 lub 9.
— Xavier Guzman

34
$(this)[0]jest tylko aliasem this, więc new FormData(this)powinno wystarczyć.
— r3wt,

9
Wydaje się, że nie jest możliwe sprawdzenie obiektu FormData, zobacz to pytanie (dla każdego, kto ma taką samą bezradność jak ja, ponieważ obiekt był zawsze pusty).
— Laura,

28
Dla przyszłych czytelników: deklaracje contentType i processData są ważne. Zobacz tę odpowiedź, aby uzyskać więcej informacji.
— AaronSieb

5
async: falsewydaje się, że nie jest to wymagane do działania i powoduje blokowanie w mobilnych przeglądarkach (jednowątkowych)
— Jeremy Daalder

33

inną opcją jest użycie elementu iframe i ustawienie dla niego celu formularza.

możesz spróbować tego (używa 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);
        });
    }
}

działa dobrze ze wszystkimi przeglądarkami, nie trzeba serializować ani przygotowywać danych. jedną wadą jest to, że nie można monitorować postępów.

także, przynajmniej w przypadku Chrome, żądanie nie pojawi się na karcie „xhr” narzędzi programistycznych, ale w „doc”


1
Rzeczywiście nie jest to Ajax, ale może być przydatne dla osób z tym samym pytaniem.
— Roey,

3
Po prostu nie mogę uwierzyć, dlaczego ta odpowiedź dostaje -2, ostatecznie skorzystałem z niej, ponieważ potrzebowałem pomocy technicznej dla starszych przeglądarek
— Sijav

Ta odpowiedź powinna znajdować się w wątku, ponieważ inne odpowiedzi wskazują, że „starsze przeglądarki nie działają” lub „można użyć hakowania iframe”, ale nigdy się do nich nie odnosi. Niezły kawałek kodu, pokazujący także, jak poprawnie używać onload +1
— mschr

18

Miałem ten sam problem w ASP.Net MVC z HttpPostedFilebase i zamiast używać formularza w Prześlij, musiałem użyć przycisku po kliknięciu w miejscu, w którym musiałem zrobić kilka rzeczy, a następnie, jeśli wszystko w porządku, prześlij formularz, więc oto jak to działa

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

spowoduje to prawidłowe wypełnienie modelu MVC, upewnij się, że w modelu właściwość HttpPostedFileBase [] ma taką samą nazwę jak nazwa kontrolki wejściowej w html, tj.

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

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

1
Oszczędzasz czas. :)
— Suhail Mumtaz Awan,

W moim przypadku musiałem użyć:contentType : "application/octet-stream"
— Christophe Roussy

Dzięki stary! Zaoszczędziłeś dużo czasu.
— Odmowa dostępu

Działa z Django, miło!
— csandreas1

Dzięki stary! Poniższe 2 wiersze działały dla mnie. var form = $ („# Form”); var formData = new FormData (formularz [0]);
— Rajiv Kumar

15

Lub krócej:

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

w ten sposób, jak sprawdzić poprawność pola danych przy użyciu tego samego skryptu, to znaczy, jeśli masz pole tekstowe i pole pliku w formularzu
— George

6

Dla mnie nie działało bez enctype: 'multipart/form-data'pola w żądaniu Ajax. Mam nadzieję, że pomoże to komuś, kto tkwi w podobnym problemie.

Chociaż z jakiegoś powodu enctype zostało już ustawione w atrybucie formularza , żądanie Ajax nie zidentyfikowało automatycznie enctypebez wyraźnej deklaracji (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>

Jak wspomniano powyżej, należy również zwrócić szczególną uwagę na pola contentTypei processData.


1
„Dla mnie nie działało bez pola enctype:„ multipart / form-data ”w żądaniu Ajax.” - To nie mogło mieć żadnego efektu. To nie jest właściwość rozpoznawana przez jQuery.ajax. Zobacz dokumentację, w której enctypew ogóle nie wspomniano.
— Quentin

Jak wspomniałem wcześniej, próbowałem wielu różnych odpowiedzi, ale one nie działały. Błąd Ajax stwierdzający błąd kodowania został pokazany w konsoli JS. Później wykonałem ten samouczek, który w końcu sprawił, że mój kod zadziałał i opublikowałem go tutaj. Być może enctypez jakiegoś powodu pole nie jest uwzględnione w dokumentacji. Nie sprawdziłem kodu źródłowego jQuery, więc nie mogę powiedzieć z całą pewnością.
— Adithya Upadhya

„Być może z jakiegoś powodu pole kodu nie jest uwzględnione w dokumentacji”. - Powodem jest to, że jQuery nic z tym nie robi, więc to nonsens.
— Quentin

Być może mógłbyś skontaktować się z Mkyongiem i zamiast tego porozmawiać z nim. Przetestowałem mój kod ponownie, usuwając enctypepole i nie przesyła on już plików (zwraca błąd typu kodowania). Nie jestem pewien, jak to działa, ponieważ nie sprawdziłem kodu źródłowego jQuery. Zamieściłem tę odpowiedź z zamiarem pomocy innym, którzy tkwią w podobnym problemie. Nie szukam tutaj głosów pozytywnych ... Jeśli masz dodatkowe pytania / komentarze, porozmawiajmy zamiast komentować.
— Adithya Upadhya

1

Dla mnie następujący kod działa

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

W metodzie Action Post przekaż parametr jako HttpPostedFileBase UploadFile i upewnij się, że dane wejściowe pliku są takie same, jak wymienione w parametrze metody akcji. Powinien również współpracować z formularzem AJAX Begin.

Pamiętaj tutaj, że Twój formularz AJAX BEGIN nie będzie tutaj działał, ponieważ wykonujesz połączenie pocztowe zdefiniowane w powyższym kodzie i możesz odwoływać się do metody w kodzie zgodnie z wymaganiami

Wiem, że odpowiadam późno, ale to zadziałało dla mnie


1

Prosty, ale bardziej skuteczny sposób:
new FormData()sam w sobie jest jak pojemnik (lub torba). Możesz umieścić wszystko attr lub plik w sobie. Jedyne, czego potrzebujesz, to dołączyć attribute, file, fileNamenp .:

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

i po prostu przekaż go w żądaniu AJAX. Na przykład:

    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')
        }
    })

Możesz dodać n liczby plików lub danych za pomocą FormData.

a jeśli tworzysz żądanie AJAX z pliku Script.js do pliku trasy w Node.js, strzeż się korzystania
req.bodyz dostępu do danych (tj. tekstu) w
req.filescelu uzyskania dostępu do pliku (np. obrazu, wideo itp.)


-1

W moim przypadku musiałem złożyć żądanie POST, które zawierało informacje przesłane przez nagłówek, a także plik wysłany przy użyciu obiektu FormData.

Sprawiłem, że działało, używając kombinacji kilku odpowiedzi tutaj, więc w zasadzie to, co skończyło się działaniem, zawierało pięć wierszy w moim żądaniu Ajax:

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

Gdzie formData była zmienną utworzoną w ten sposób:

 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",jest aktywnie szkodliwy, a jedynym powodem, dla którego nie powoduje problemu, jest nadpisanie go dwie linie później.
— Quentin

1
enctype: 'multipart/form-data',jest bezcelowe. jQuery.ajax nie rozpoznaje tego parametru.
— Quentin

… Reszta twojej odpowiedzi nie obejmuje „danych” bitów „danych i plików” z tytułu pytania.
— Quentin

-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);
?>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.