Ajaxを使用してデータとファイルの両方を1つの形式でアップロードしますか?


384

フォームにjQueryとAjaxを使用してデータとファイルを送信していますが、データとファイルの両方を1つのフォームで送信する方法がわかりません。

私は現在両方の方法でほとんど同じことをしていますが、データが配列に収集される方法は異なり、データは使用します.serialize();がファイルは使用します= new FormData($(this)[0]);

Ajaxを介してファイルとデータを1つの形式でアップロードできるようにするために、両方の方法を組み合わせることが可能ですか?

データ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を介して1つの形式でデータとファイルを送信できるように、上記をどのように組み合わせることができますか?

私の目的は、このフォームのすべてをAjaxで1つの投稿で送信できるようにすることです。それは可能ですか?

<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どっち?シリアライズ付きのものはデータに対してのみ機能するようですが、もう一方はファイルに対してのみ機能するようです?
Dan

このMDNページによる判断で、使用時にすべてのフォームデータを送信する必要がありますFormData
lanzz

1
@lanzzあなたは正しい、それは私が間違ったフォームIDを使用しているはずだと私が思ったように機能します、あなたはajaxで1つのフォームを介してファイルとデータの両方をアップロードできます。
Dan

これは、複数選択のファイル入力がある場合は機能しないようです。最初のファイルのみがアップロードされます。
Sami Al-Subhi

回答:


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
いるFormDataはない、IE 8または9に存在するHTML5オブジェクトであるとしてIE <10この溶液のバージョンでは、動作しません
ザビエルグスマン

34
$(this)[0]は単なるのエイリアスなthisので、new FormData(this)十分なはずです。
r3wt 14

9
FormDataオブジェクトを検査することはできないようです。この質問を参照してください(オブジェクトが常に空だったため、私が行ったのと同じ無知に遭遇している人は誰でも)。
ローラ

28
今後の読者のために:contentTypeとprocessDataの宣言は重要です。詳細については、この回答を参照してください。
AaronSieb 2015

5
これはasync: false機能するために必要ではないようで、モバイル(シングルスレッド)ブラウザーでブロッキングを引き起こします
Jeremy Daalder '21

34

別のオプションは、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);
        });
    }
}

すべてのブラウザで問題なく機能するため、データをシリアル化または準備する必要はありません。1つの欠点は、進行状況を監視できないことです。

また、少なくともchromeの場合、リクエストは開発者ツールの「xhr」タブではなく「doc」の下に表示されます


1
確かにそれはAjaxではありませんが、同じ質問を持つ人々にとってはまだ役に立ちます。
Roey 2016

3
なぜこの答えが-2になるのか信じられません。レガシーブラウザのサポートが必要だったので、これを使用してしまいました
Sijav

他の回答は「古いブラウザは機能しない」または「iframeハックが使用される可能性がある」と指摘しているが、それらに対処していないため、この回答はスレッド内にある必要があります。素敵なコード、onloadを正しく使用する方法も示しています+1
mschr

18

私はHttpPostedFilebaseを使用してASP.Net MVCでこれと同じ問題を抱えていましたが、送信でフォームを使用する代わりに、何かを行う必要がある場所でクリック時にボタンを使用する必要がありました。

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

1
あなたは時間の節約になります。:)
Suhail Mumtaz Awan

私の場合、使用しなければなりませんでした:contentType : "application/octet-stream"
Christophe Roussy

ありがとう!時間を大幅に節約できました。
アクセス拒否

Djangoで動作します。
csandreas1

相棒、ありがとな!以下の2行でうまくいきました。var form = $( "#Form"); var formData = new FormData(form [0]);
Rajiv Kumar

15

またはより短い:

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

これで、同じスクリプトを使用してデータフィールドを検証する方法は、フォームにテキストフィールドとファイルフィールドがある場合です
George

6

私にとってenctype: 'multipart/form-data'は、Ajaxリクエストのフィールドなしでは機能しませんでした。同様の問題で困っている人の助けになることを願っています。

enctype はすでにform属性設定されていました、何らかの理由で、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
「私にとっては、Ajaxリクエストのenctype: 'multipart / form-data'フィールドがないと機能しませんでした。」—それは効果がなかったはずです。jQuery.ajaxが認識するプロパティではありません。参照ドキュメントenctypeまったく言及されていないが。
クエンティン

前に述べたように、私は複数の異なる答えを試しましたが、うまくいきませんでした。エンコーディングエラーを示すAjaxエラーがJSコンソールに表示されました。後で私はこのチュートリアルに従って最終的にコードを機能させ、ここに投稿しました。おそらく、enctypeフィールドは理由のためにドキュメントでカバーされていません。私はjQueryのソースコードをチェックしていないので、はっきりとは言えません。
Adithya Upadhya

「おそらく、enctypeフィールドは、何らかの理由でドキュメントに記載されていません。」—その理由は、jQueryがjQueryで何も実行しないため、意味がないからです。
クエンティン、

おそらく、代わりにMkyongに連絡して、彼と会話することができます。enctypeフィールドを削除してコードを再度テストしたところ、ファイルがアップロードされなくなりました(エンコードタイプのエラーが返されます)。jQueryのソースコードをチェックしていないので、それがどのように機能するかわかりません。私は同様の問題で立ち往生している他の人を助けることを意図してこの回答を投稿しました。ここで賛成投票をするつもりはありません...さらに質問やコメントがある場合は、コメントするのではなくチャットしましょう。
Adithya Upadhya

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フォームでも動作するはずです。

上記のコードで定義されたpost呼び出しを行い、要件に従ってコードでメソッドを参照できるため、AJAX BEGINフォームはここでは機能しません。

私は遅く答えていることを知っていますが、これは私のために働いたものです


1

シンプルだがより効果的な方法:
new FormData()それ自体がコンテナー(またはバッグ)のようなものです。すべてのattrまたはfileをそれ自体に置くことができます。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')
        }
    })

FormDataを使用して、n個のファイルまたはデータを追加できます。

Script.jsファイルからNode.jsのルートファイルへのAJAXリクエストを作成する場合は、
req.bodyデータ(テキスト)
req.filesにアクセスしてファイル(画像、ビデオなど)にアクセスするのに注意してください。


-1

私の場合、ヘッダーを介して送信された情報と、FormDataオブジェクトを使用して送信されたファイルを含むPOSTリクエストを作成する必要がありました。

私はここでいくつかの答えを組み合わせて使用​​してそれを機能させたので、基本的にはAjaxリクエストに次の5行が含まれていた。

 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",は積極的に有害であり、問​​題を引き起こさない唯一の理由は、2行後で上書きするためです。
クエンティン

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);
?>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.