570 Stimmen

Wie sendet man FormData-Objekte mit Ajax-Anfragen in jQuery?

El XMLHttpRequest Stufe 2 Standard (noch ein Arbeitsentwurf) definiert die FormData Schnittstelle. Diese Schnittstelle ermöglicht das Anhängen von File Objekte zu XHR-Anfragen (Ajax-Anfragen).

Dies ist übrigens eine neue Funktion - in der Vergangenheit wurde der "hidden-iframe-trick" verwendet (lesen Sie darüber in meine andere Frage ).

So funktioniert es (Beispiel):

var xhr = new XMLHttpRequest(),
    fd = new FormData();

fd.append( 'file', input.files[0] );
xhr.open( 'POST', 'http://example.com/script.php', true );
xhr.onreadystatechange = handler;
xhr.send( fd );

donde input es un <input type="file"> Feld, und handler ist der Success-Handler für die Ajax-Anfrage.

Dies funktioniert in allen Browsern (wieder mit Ausnahme des IE) hervorragend.

Nun möchte ich diese Funktionalität mit jQuery zum Laufen bringen. Ich habe dies versucht:

var fd = new FormData();    
fd.append( 'file', input.files[0] );

$.post( 'http://example.com/script.php', fd, handler );

Leider funktioniert das nicht (es wird ein "Illegaler Aufruf"-Fehler ausgegeben - Screenshot ist hier ). Ich gehe davon aus, dass jQuery ein einfaches Key-Value-Objekt erwartet, das Formularfeld-Namen/Werte repräsentiert, und die FormData Instanz, die ich eingebe, ist offenbar nicht kompatibel.

Da es nun möglich ist, eine FormData Instanz in xhr.send() Ich hoffe, dass es auch möglich ist, es mit jQuery funktionieren zu lassen.


Aktualisierung:

Ich habe ein "Feature-Ticket" bei jQuery's Bug Tracker erstellt. Es ist hier: http://bugs.jquery.com/ticket/9995

Mir wurde vorgeschlagen, einen "Ajax-Vorfilter" zu verwenden...


Aktualisierung:

Lassen Sie mich zunächst anhand einer Demo zeigen, welches Verhalten ich erreichen möchte.

HTML:

<form>
    <input type="file" id="file" name="file">
    <input type="submit">
</form>

JavaScript:

$( 'form' ).submit(function ( e ) {
    var data, xhr;

    data = new FormData();
    data.append( 'file', $( '#file' )[0].files[0] );

    xhr = new XMLHttpRequest();

    xhr.open( 'POST', 'http://hacheck.tel.fer.hr/xml.pl', true );
    xhr.onreadystatechange = function ( response ) {};
    xhr.send( data );

    e.preventDefault();
});

Der obige Code führt zu dieser HTTP-Anfrage:

multipartformdata

Das ist es, was ich brauche - Ich will den Inhaltstyp "multipart/form-data"!


Die vorgeschlagene Lösung würde folgendermaßen aussehen:

$( 'form' ).submit(function ( e ) {
    var data;

    data = new FormData();
    data.append( 'file', $( '#file' )[0].files[0] );

    $.ajax({
        url: 'http://hacheck.tel.fer.hr/xml.pl',
        data: data,
        processData: false,
        type: 'POST',
        success: function ( data ) {
            alert( data );
        }
    });

    e.preventDefault();
});

Dies führt jedoch zu:

wrongcontenttype

Wie Sie sehen können, ist der Inhaltstyp falsch...

1019voto

pradeek Punkte 20665

Ich glaube, man könnte es so machen:

var fd = new FormData();    
fd.append( 'file', input.files[0] );

$.ajax({
  url: 'http://example.com/script.php',
  data: fd,
  processData: false,
  contentType: false,
  type: 'POST',
  success: function(data){
    alert(data);
  }
});

Anmerkungen:

  • Einstellung processData à false können Sie verhindern, dass jQuery die Daten automatisch in einen Query-String umwandelt. Siehe die Dokumente für weitere Informationen.

  • Einstellung der contentType à false ist zwingend erforderlich, da sonst jQuery wird es falsch eingestellt .

34voto

Lucky Punkte 15797

Sie können das FormData-Objekt mit folgendem Code in einer Ajax-Anfrage senden,

$("form#formElement").submit(function(){
    var formData = new FormData($(this)[0]);
});

Dies ist der akzeptierten Antwort sehr ähnlich, aber eine echte Antwort auf das Thema der Frage. Dadurch werden die Formularelemente automatisch an die FormData-Variable übermittelt und Sie müssen die Daten nicht manuell an die FormData-Variable anhängen.

Die Ajax-Methode sieht wie folgt aus,

$("form#formElement").submit(function(){
    var formData = new FormData($(this)[0]);
    //append some non-form data also
    formData.append('other_data',$("#someInputData").val());
    $.ajax({
        type: "POST",
        url: postDataUrl,
        data: formData,
        processData: false,
        contentType: false,
        dataType: "json",
        success: function(data, textStatus, jqXHR) {
           //process data
        },
        error: function(data, textStatus, jqXHR) {
           //process error msg
        },
});

Sie können das Formularelement auch manuell innerhalb des FormData-Objekts als Parameter wie folgt übergeben

var formElem = $("#formId");
var formdata = new FormData(formElem[0]);

Ich hoffe, es hilft ;)

31voto

BenSwayne Punkte 16682

Es gibt einige noch zu erwähnende Techniken, die Ihnen zur Verfügung stehen. Beginnen Sie mit der Einstellung der Eigenschaft contentType in Ihren Ajax-Parametern.

Aufbauend auf dem Beispiel von Pradeek:

$('form').submit(function (e) {
    var data;

    data = new FormData();
    data.append('file', $('#file')[0].files[0]);

    $.ajax({
        url: 'http://hacheck.tel.fer.hr/xml.pl',
        data: data,
        processData: false,
        type: 'POST',

        // This will override the content type header, 
        // regardless of whether content is actually sent.
        // Defaults to 'application/x-www-form-urlencoded'
        contentType: 'multipart/form-data', 

        //Before 1.5.1 you had to do this:
        beforeSend: function (x) {
            if (x && x.overrideMimeType) {
                x.overrideMimeType("multipart/form-data");
            }
        },
        // Now you should be able to do this:
        mimeType: 'multipart/form-data',    //Property added in 1.5.1

        success: function (data) {
            alert(data);
        }
    });

    e.preventDefault();
});

In einigen Fällen, in denen jQuery ajax dazu gezwungen wird, nicht erwartete Dinge zu tun, kann die beforeSend Veranstaltung ist ein großartiger Ort, um dies zu tun. Eine Zeit lang benutzten die Leute beforeSend um den mimeType zu überschreiben, bevor dieser in jQuery in 1.5.1 hinzugefügt wurde. Sie sollten in der Lage sein, so ziemlich alles auf dem jqXHR-Objekt in der vor dem Senden Ereignis zu ändern.

7voto

talalalshehri Punkte 135

Ich mache es so und es funktioniert bei mir, ich hoffe das hilft :)

   <div id="data">
        <form>
            <input type="file" name="userfile" id="userfile" size="20" />
            <br /><br />
            <input type="button" id="upload" value="upload" />
        </form>
    </div>
  <script>
        $(document).ready(function(){
                $('#upload').click(function(){

                    console.log('upload button clicked!')
                    var fd = new FormData();    
                    fd.append( 'userfile', $('#userfile')[0].files[0]);

                    $.ajax({
                      url: 'upload/do_upload',
                      data: fd,
                      processData: false,
                      contentType: false,
                      type: 'POST',
                      success: function(data){
                        console.log('upload success!')
                        $('#data').empty();
                        $('#data').append(data);

                      }
                    });
                });
        });
    </script>

5voto

Rahul Yadav Punkte 697

JavaScript:

function submitForm() {
    var data1 = new FormData($('input[name^="file"]'));
    $.each($('input[name^="file"]')[0].files, function(i, file) {
        data1.append(i, file);
    });

    $.ajax({
        url: "<?php echo base_url() ?>employee/dashboard2/test2",
        type: "POST",
        data: data1,
        enctype: 'multipart/form-data',
        processData: false, // tell jQuery not to process the data
        contentType: false // tell jQuery not to set contentType
    }).done(function(data) {
        console.log("PHP Output:");
        console.log(data);
    });
    return false;
}

PHP:

public function upload_file() {
    foreach($_FILES as $key) {
        $name = time().$key['name'];
        $path = 'upload/'.$name;
        @move_uploaded_file($key['tmp_name'], $path);
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X