Mengunggah data dan file dalam satu bentuk menggunakan Ajax?

384

Saya menggunakan jQuery dan Ajax untuk formulir saya untuk mengirim data dan file tetapi saya tidak yakin bagaimana mengirim data dan file dalam satu formulir?

Saat ini saya melakukan hampir sama dengan kedua metode tetapi cara di mana data dikumpulkan ke dalam array berbeda, data menggunakan .serialize();tetapi file menggunakan= new FormData($(this)[0]);

Apakah mungkin untuk menggabungkan kedua metode agar dapat mengunggah file dan data dalam satu bentuk melalui Ajax?

Data jQuery, Ajax dan 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>

File jQuery, Ajax dan 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>

Bagaimana saya bisa menggabungkan di atas sehingga saya dapat mengirim data dan file dalam satu bentuk melalui Ajax?

Tujuan saya adalah untuk dapat mengirim semua formulir ini dalam satu posting dengan Ajax, mungkinkah?

<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>
Dan
sumber
2
The FormDataPendekatan harus bekerja dengan baik dengan bentuk-bentuk yang mengandung apa pun yang Anda inginkan, bukan hanya bidang upload file; itu tidak didukung secara luas sekalipun.
lanzz
@lanzz yang mana? yang dengan serialisasi tampaknya hanya berfungsi untuk data tetapi yang lain tampaknya hanya berfungsi untuk file?
Dan
Dilihat oleh halaman MDN ini , semua data formulir harus diserahkan saat Anda menggunakanFormData
lanzz
1
@lanzz Anda benar, itu berfungsi bagaimana saya pikir seharusnya saya menggunakan id formulir yang salah, Anda dapat mengunggah file dan data melalui satu formulir dengan ajax.
Dan
Ini sepertinya tidak berfungsi ketika ada input file multi-pilih. Itu hanya mengunggah file pertama.
Sami Al-Subhi

Jawaban:

458

Masalah yang saya miliki adalah menggunakan pengidentifikasi jQuery yang salah.

Anda dapat mengunggah data dan file dengan satu formulir menggunakan 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
    });
});

Versi pendek

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

    $.post($(this).attr("action"), formData, function(data) {
        alert(data);
    });
});
Dan
sumber
17
dalam versi IE <10 solusi ini tidak akan berfungsi, karena FormData adalah objek HTML5, tidak ada di IE 8 atau 9.
Xavier Guzman
34
$(this)[0]hanya alias this, jadi new FormData(this)harus cukup.
r3wt
9
Tampaknya tidak mungkin untuk memeriksa ObjectData Object, lihat pertanyaan ini (bagi siapa pun yang berjalan ke cluelessness yang sama seperti yang baru saja saya lakukan karena Object selalu kosong).
Laura
28
Untuk pembaca mendatang: deklarasi contentType dan processData penting. Lihat jawaban ini untuk informasi lebih lanjut.
AaronSieb
5
yang async: falsetampaknya tidak diperlukan untuk ini untuk bekerja dan menyebabkan pemblokiran di ponsel (single threaded) browser
Jeremy Daalder
34

Pilihan lain adalah menggunakan iframe dan mengatur target form untuk itu.

Anda dapat mencoba ini (menggunakan 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);
        });
    }
}

ini bekerja dengan baik dengan semua browser, Anda tidak perlu membuat cerita bersambung atau menyiapkan data. satu kelemahannya adalah Anda tidak dapat memantau perkembangannya.

juga, setidaknya untuk chrome, permintaan tidak akan muncul di tab "xhr" pada alat pengembang tetapi di bawah "doc"

Roey
sumber
1
Memang bukan Ajax, tetap bisa bermanfaat bagi orang dengan pertanyaan yang sama.
Roey
3
Saya hanya tidak percaya mengapa jawaban ini didapat -2, saya akhirnya menggunakan ini karena saya membutuhkan dukungan browser lama
Sijav
Jawaban ini harus ada di utas karena jawaban lain mencatat 'peramban lama tidak berfungsi' atau 'peretasan iframe dapat digunakan' tetapi tidak pernah mengatasinya. Sepotong kode yang bagus, juga menunjukkan cara menggunakan onload dengan benar +1
mschr
18

Saya mengalami masalah yang sama di ASP.Net MVC dengan HttpPostedFilebase dan alih-alih menggunakan formulir Kirim saya harus menggunakan tombol klik di mana saya perlu melakukan beberapa hal dan kemudian jika semua OK kirimkan formulir jadi di sini adalah bagaimana saya membuatnya bekerja

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

ini akan daripada benar mengisi model MVC Anda, pastikan dalam Model Anda, Properti untuk HttpPostedFileBase [] memiliki nama yang sama dengan Nama kontrol input dalam html yaitu

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

public class MyViewModel
{
    public HttpPostedFileBase[] UploadedFiles { get; set; }
}
h_power11
sumber
1
Anda adalah penghemat waktu. :)
Suhail Mumtaz Awan
Dalam kasus saya, saya harus menggunakan:contentType : "application/octet-stream"
Christophe Roussy
Terimakasih kawan! Anda menghemat banyak waktu.
Akses Ditolak
Ini bekerja dengan Django, bagus!
csandreas1
Terima kasih sobat! 2 baris di bawah ini bekerja untuk saya. var form = $ ("# Form"); var formData = FormData baru (form [0]);
Rajiv Kumar
15

Atau lebih pendek:

$("form#data").submit(function() {
    var formData = new FormData(this);
    $.post($(this).attr("action"), formData, function() {
        // success    
    });
    return false;
});
schaenk
sumber
jadi dengan ini, bagaimana Anda memvalidasi bidang data menggunakan skrip yang sama, yaitu jika Anda memiliki bidang teks dan bidang file di formulir Anda
George
6

Bagi saya, itu tidak berfungsi tanpa enctype: 'multipart/form-data'bidang dalam permintaan Ajax. Saya harap ini membantu seseorang yang terjebak dalam masalah yang sama.

Meskipun enctype sudah ditetapkan dalam atribut form , untuk beberapa alasan, permintaan Ajax tidak secara otomatis mengidentifikasi enctypetanpa deklarasi eksplisit (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>

Seperti yang disebutkan di atas, harap juga memberikan perhatian khusus pada bidang contentTypedan processData.

Adithya Upadhya
sumber
1
"Bagi saya, itu tidak berfungsi tanpa enctype: bidang 'multipart / formulir-data' dalam permintaan Ajax." - Itu tidak mungkin memiliki efek apa pun. Ini bukan properti yang dikenali oleh jQuery.ajax. Lihat dokumentasi di mana enctypetidak disebutkan sama sekali.
Quentin
Seperti yang saya sebutkan sebelumnya, saya mencoba beberapa jawaban berbeda tetapi gagal berfungsi. Kesalahan Ajax yang menyatakan kesalahan penyandian ditampilkan di konsol JS. Kemudian saya mengikuti tutorial ini yang akhirnya membuat kode saya berfungsi dan saya mempostingnya di sini. Mungkin, enctypebidang tidak tercakup dalam dokumentasi karena suatu alasan. Saya belum memeriksa kode sumber jQuery jadi saya tidak bisa mengatakan dengan pasti.
Adithya Upadhya
"Mungkin, bidang enctype tidak tercakup dalam dokumentasi karena suatu alasan." - Alasannya adalah bahwa jQuery tidak melakukan apa-apa dengannya sehingga tidak masuk akal.
Quentin
Mungkin Anda bisa menghubungi Mkyong sebagai gantinya. Saya menguji kode saya lagi dengan menghapus enctypebidang dan tidak lagi mengunggah file (jenis kesalahan pengkodean kembali). Saya tidak yakin cara kerjanya karena saya belum memeriksa kode sumber jQuery. Saya memposting jawaban ini dengan tujuan membantu orang lain yang terjebak dalam masalah yang sama. Saya tidak memancing upvote di sini ... Jika Anda memiliki pertanyaan / komentar lebih lanjut, mari kita mengobrol daripada berkomentar.
Adithya Upadhya
1

Bagi saya mengikuti pekerjaan kode

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

Dalam Metode Postingan Anda, sampaikan parameter sebagai HttpPostedFileBase UploadFile dan pastikan input file Anda sama seperti yang disebutkan dalam parameter Anda pada Metode Tindakan. Ini harus bekerja dengan formulir Mulai AJAX juga.

Ingat di sini bahwa Formulir AJAX BEGIN Anda tidak akan berfungsi di sini karena Anda membuat panggilan pos Anda didefinisikan dalam kode yang disebutkan di atas dan Anda dapat referensi metode Anda dalam kode sesuai Kebutuhan.

Saya tahu saya menjawab terlambat tetapi ini yang berhasil bagi saya

Pranav Kulshrestha
sumber
1

Cara sederhana tetapi lebih efektif:
new FormData()itu sendiri seperti wadah (atau tas). Anda dapat meletakkan semuanya attr atau file dengan sendirinya. Satu-satunya hal yang Anda perlu tambahkan attribute, file, fileNamemisalnya:

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

dan kirimkan saja dalam permintaan AJAX. Misalnya:

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

Anda dapat menambahkan sejumlah file atau data dengan FormData.

dan jika Anda membuat Permintaan AJAX dari file Script.js untuk merutekan file di Node.js jangan gunakan
req.bodyuntuk mengakses data (yaitu teks)
req.filesuntuk mengakses file (yaitu gambar, video dll)

kartik tyagi
sumber
-1

Dalam kasus saya, saya harus membuat permintaan POST, yang memiliki informasi yang dikirim melalui header, dan juga file yang dikirim menggunakan objek FormData.

Saya membuatnya bekerja menggunakan kombinasi dari beberapa jawaban di sini, jadi pada dasarnya apa yang akhirnya berhasil adalah memiliki lima baris ini dalam permintaan Ajax saya:

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

Di mana formData adalah variabel yang dibuat seperti ini:

 var file = document.getElementById('uploadedFile').files[0];
 var form = $('form')[0];
 var formData = new FormData(form);
 formData.append("File", file);
ndarriulat
sumber
1
contentType: "application/octet-stream",aktif berbahaya dan satu-satunya alasan tidak menyebabkan masalah adalah karena Anda menimpanya dua baris nanti.
Quentin
1
enctype: 'multipart/form-data',tidak ada gunanya. jQuery.ajax tidak mengenali paramater itu.
Quentin
... sisa jawaban Anda gagal untuk menutupi "data" sedikit "data dan file" dari judul pertanyaan.
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);
?>
Shailesh Dwivedi
sumber