Hochladen von Daten und Dateien in einer Form mit Ajax?

384

Ich verwende jQuery und Ajax für meine Formulare, um Daten und Dateien zu senden, bin mir aber nicht sicher, wie ich Daten und Dateien in einem Formular senden soll?

Ich mache derzeit fast dasselbe mit beiden Methoden, aber die Art und Weise, wie die Daten in einem Array gesammelt werden, ist unterschiedlich, die Daten werden verwendet, .serialize();aber die Dateien= new FormData($(this)[0]);

Ist es möglich, beide Methoden zu kombinieren, um Dateien und Daten über Ajax in einer Form hochladen zu können?

Daten jQuery, Ajax und 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>

Dateien jQuery, Ajax und 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>

Wie kann ich das oben Genannte kombinieren, um Daten und Dateien in einem Formular über Ajax zu senden?

Mein Ziel ist es, all dieses Formular in einem Post mit Ajax senden zu können. Ist das möglich?

<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
quelle
2
Der FormDataAnsatz sollte gut mit Formularen funktionieren, die alles enthalten, was Sie wollen, nicht nur die Felder zum Hochladen von Dateien. es wird jedoch nicht allgemein unterstützt.
Lanzz
@lanzz was aber? der eine mit serialize scheint nur für Daten zu funktionieren, der andere scheint nur für Dateien zu funktionieren?
Dan
Gemessen an dieser MDN-Seite sollten alle Formulardaten übermittelt werden, wenn SieFormData
lanzz
1
@lanzz Sie haben Recht, es funktioniert so, wie ich es mir vorgestellt habe. Ich habe die falsche Formular-ID verwendet. Sie können sowohl Dateien als auch Daten über ein Formular mit Ajax hochladen.
Dan
Dies scheint nicht zu funktionieren, wenn eine Mehrfachauswahl-Dateieingabe erfolgt. Es wird nur die erste Datei hochgeladen.
Sami Al-Subhi

Antworten:

458

Das Problem, das ich hatte, war die Verwendung der falschen jQuery-ID.

Mit ajax können Sie Daten und Dateien mit einem Formular hochladen .

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

Kurzfassung

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

    $.post($(this).attr("action"), formData, function(data) {
        alert(data);
    });
});
Dan
quelle
17
In Versionen von IE <10 funktioniert diese Lösung nicht, da FormData ein HTML5-Objekt ist, das in IE 8 oder 9 nicht vorhanden ist.
Xavier Guzman
34
$(this)[0]ist nur ein Alias ​​von this, new FormData(this)sollte also ausreichen.
r3wt
9
Es scheint nicht möglich zu sein, das FormData-Objekt zu untersuchen, siehe diese Frage (für alle, die in die gleiche Ahnungslosigkeit geraten wie ich, weil das Objekt immer leer war).
Laura
28
Für zukünftige Leser: Die Deklarationen contentType und processData sind wichtig. Weitere Informationen finden Sie in dieser Antwort .
AaronSieb
5
Das async: falsescheint nicht erforderlich zu sein, damit dies funktioniert, und führt zu Blockierungen in mobilen Browsern (Single Threaded)
Jeremy Daalder
33

Eine andere Möglichkeit besteht darin, einen Iframe zu verwenden und das Ziel des Formulars darauf festzulegen.

Sie können dies versuchen (es verwendet 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);
        });
    }
}

Es funktioniert gut mit allen Browsern. Sie müssen die Daten nicht serialisieren oder vorbereiten. Ein Nachteil ist, dass Sie den Fortschritt nicht überwachen können.

Zumindest für Chrome wird die Anforderung nicht auf der Registerkarte "xhr" der Entwicklertools angezeigt, sondern unter "doc".

Roey
quelle
1
In der Tat ist es nicht Ajax, kann immer noch für Menschen mit der gleichen Frage nützlich sein.
Roey
3
Ich kann einfach nicht glauben, warum diese Antwort -2 erhält.
Am
Diese Antwort sollte im Thread enthalten sein, da andere Antworten "ältere Browser funktionieren nicht" oder "iframe-Hack könnte verwendet werden", aber niemals ansprechen. Netter Code, der auch zeigt, wie man Onload richtig benutzt +1
mschr
18

Ich hatte das gleiche Problem in ASP.Net MVC mit HttpPostedFilebase und anstatt das Formular beim Senden zu verwenden, musste ich die Schaltfläche beim Klicken verwenden, wo ich einige Dinge tun musste, und wenn alles in Ordnung ist, hat das Senden-Formular hier funktioniert

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

Dadurch wird Ihr MVC-Modell korrekt ausgefüllt. Stellen Sie in Ihrem Modell sicher, dass die Eigenschaft für HttpPostedFileBase [] denselben Namen hat wie der Name des Eingabesteuerelements in HTML, d. h

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

public class MyViewModel
{
    public HttpPostedFileBase[] UploadedFiles { get; set; }
}
h_power11
quelle
1
Sie sparen Zeit. :)
Suhail Mumtaz Awan
In meinem Fall musste ich verwenden:contentType : "application/octet-stream"
Christophe Roussy
Danke Kumpel! Sie haben viel Zeit gespart.
Zugriff verweigert
Es funktioniert mit Django, schön!
csandreas1
Danke Kumpel! Die folgenden 2 Zeilen haben bei mir funktioniert. var form = $ ("# Form"); var formData = new FormData (form [0]);
Rajiv Kumar
15

Oder kürzer:

$("form#data").submit(function() {
    var formData = new FormData(this);
    $.post($(this).attr("action"), formData, function() {
        // success    
    });
    return false;
});
schaenk
quelle
Wie können Sie also ein Datenfeld mit demselben Skript validieren, wenn Sie ein Textfeld und ein Dateifeld in Ihrem Formular haben
George
6

Für mich hat es ohne enctype: 'multipart/form-data'Feld in der Ajax-Anfrage nicht funktioniert . Ich hoffe, es hilft jemandem, der in einem ähnlichen Problem steckt.

Obwohl das enctype bereits im Formularattribut festgelegt wurde, hat die Ajax-Anforderung aus irgendeinem Grund das enctypeohne explizite Deklaration nicht automatisch identifiziert (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>

Wie bereits erwähnt, achten Sie bitte auch besonders auf die Felder contentTypeund processData.

Adithya Upadhya
quelle
1
"Für mich hat es ohne enctype: 'multipart / form-data' Feld in der Ajax-Anfrage nicht funktioniert." - Das kann keine Wirkung gehabt haben. Es ist keine von jQuery.ajax erkannte Eigenschaft. Siehe die Dokumentation, in der überhaupt enctypenichts erwähnt wird.
Quentin
Wie ich bereits erwähnt habe, habe ich mehrere verschiedene Antworten ausprobiert, aber sie haben nicht funktioniert. In der JS-Konsole wurde ein Ajax-Fehler angezeigt, der einen Codierungsfehler angibt. Später folgte ich diesem Tutorial, wodurch mein Code endlich funktionierte und ich es hier veröffentlichte. Möglicherweise wird das enctypeFeld aus einem bestimmten Grund nicht in der Dokumentation behandelt. Ich habe den jQuery-Quellcode nicht überprüft, daher kann ich nicht mit Sicherheit sagen.
Adithya Upadhya
"Möglicherweise wird das Feld enctype aus einem bestimmten Grund nicht in der Dokumentation behandelt." - Der Grund dafür ist, dass jQuery nichts damit macht, also ist es Unsinn.
Quentin
Vielleicht könnten Sie Mkyong kontaktieren und stattdessen ein Gespräch mit ihm führen. Ich habe meinen Code erneut getestet, indem ich das enctypeFeld entfernt habe, und es werden keine Dateien mehr hochgeladen (Fehler beim Codierungstyp werden zurückgegeben). Ich bin mir nicht sicher, wie das funktioniert, da ich den jQuery-Quellcode nicht überprüft habe. Ich habe diese Antwort mit der Absicht gepostet, anderen zu helfen, die in einem ähnlichen Problem stecken. Ich fische hier nicht nach Upvotes ... Wenn Sie weitere Fragen / Kommentare haben, lassen Sie uns chatten, anstatt zu kommentieren.
Adithya Upadhya
1

Für mich folgende Code-Arbeit

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

Übergeben Sie in Ihrer Action Post-Methode den Parameter als HttpPostedFileBase UploadFile und stellen Sie sicher, dass Ihre Dateieingabe mit den Angaben in Ihrem Parameter der Action Method übereinstimmt. Es sollte auch mit AJAX Begin funktionieren.

Denken Sie hier daran, dass Ihr AJAX BEGIN-Formular hier nicht funktioniert, da Sie Ihren Post-Call im oben genannten Code definiert haben und Sie Ihre Methode im Code gemäß der Anforderung referenzieren können

Ich weiß, dass ich spät antworte, aber das hat bei mir funktioniert

Pranav Kulshrestha
quelle
1

Ein einfacher, aber effektiverer Weg:
new FormData()ist selbst wie ein Behälter (oder eine Tasche). Sie können alles attr oder Datei in sich selbst setzen. Das einzige, was Sie brauchen, um das attribute, file, fileNamezB anzuhängen :

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

und einfach in AJAX-Anfrage übergeben. Z.B:

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

Mit FormData können Sie n Dateien oder Daten anhängen.

und wenn Sie eine AJAX-Anfrage von der Datei Script.js zur Routendatei in Node.js stellen, achten Sie darauf
req.body, dass Sie nicht auf Daten (z. B. Text)
req.fileszugreifen, um auf Dateien (z. B. Bild, Video usw.) zuzugreifen.

kartik tyagi
quelle
-1

In meinem Fall musste ich eine POST-Anfrage stellen, bei der Informationen über den Header gesendet wurden, sowie eine Datei, die mit einem FormData-Objekt gesendet wurde.

Ich habe es mit einer Kombination einiger der Antworten hier zum Laufen gebracht. Im Grunde ging es also darum, diese fünf Zeilen in meiner Ajax-Anfrage zu haben:

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

Wobei formData eine Variable war, die wie folgt erstellt wurde:

 var file = document.getElementById('uploadedFile').files[0];
 var form = $('form')[0];
 var formData = new FormData(form);
 formData.append("File", file);
ndarriulat
quelle
1
contentType: "application/octet-stream",ist aktiv schädlich und der einzige Grund, warum es kein Problem verursacht, ist, dass Sie es zwei Zeilen später überschreiben.
Quentin
1
enctype: 'multipart/form-data',ist sinnlos. jQuery.ajax erkennt diesen Parameter nicht.
Quentin
… Der Rest Ihrer Antwort deckt nicht das "Daten" -Bit von "Daten und Dateien" aus dem Fragentitel ab.
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
quelle