配列をFormDataに追加し、AJAX経由で送信する


108

私はajaxを使用して、配列、テキストフィールド、ファイルを含むマルチパートフォームを送信しています。

各VARをメインデータに追加します

var attachments = document.getElementById('files'); 
var data= new FormData();

for (i=0; i< attachments.files.length; i++){
    data.append('file', attachments.files[i]);
    console.log(attachments.files[i]);

    data.append ('headline', headline);
    data.append ('article', article);
    data.append ('arr', arr);
    data.append ('tag', tag);

次に、ajax関数を使用してそれをPHPファイルに送信し、SQL DB内に格納します。

$.ajax({    
    type: "post",
    url: 'php/submittionform.php',
    cache: false,
    processData: false,
    contentType: false,
    data: data,
    success: function(request) {$('#box').html(request); }
})

しかし、PHP側arrでは、配列である変数は文字列として表示されます。

ajaxでフォームデータとして送信せず、単純な$.POSTオプションを使用すると、PHP側で配列として取得しますが、ファイルも送信できません。

解決策はありますか?

回答:


92

いくつかのオプションがあります。

それをJSON文字列に変換し、PHPで解析します(推奨)

JS

var json_arr = JSON.stringify(arr);

PHP

$arr = json_decode($_POST['arr']);

または@Curiosのメソッドを使用する

を介して配列を送信するFormData


非推奨:データをシリアライズしてからPHPでデシリアライズする

JS

// Use <#> or any other delimiter you want
var serial_arr = arr.join("<#>"); 

PHP

$arr = explode("<#>", $_POST['arr']);

1
問題は、配列にスペースと句読点を含むREALテキストの行が含まれていることです。私はそれを台無しにしたくありません。
shultz 2013

3
JSONでエンコードして解析しても、データは失われません。試してみてください;)
Richard de Wit

自動マッピングなどでasp.netを使用している場合は、@ Curiousの答えが必要です。
マルティン・コル

1
@Richard de Wit FileやFormDataなどのデータがある場合、json.stringfyでそれらが失われます
Mohsen

私は文字列化された、よりシンプルなものが好きです。[]を使用して配列の配列を渡すには、ある種の再帰を行う必要がありますが、その方法で実行できることを知っておくと役に立ちます。
チョップナット

260

FormDataこの方法で配列を送ることもできます:

var formData = new FormData;
var arr = ['this', 'is', 'an', 'array'];
for (var i = 0; i < arr.length; i++) {
    formData.append('arr[]', arr[i]);
}

したがってarr[]、単純なHTMLフォームを使用する場合と同じ方法で記述できます。PHPの場合は動作するはずです。

この記事は役に立ちます:クエリ文字列内で配列を渡す方法は?


1
@Oleg書くために必要なものであるarr[]にはformData.append('arr[]', arr[i]);?なぜarr正しくないのですか?私は両方を試しましたが、arr[]うまくいきました。
トトロ

@Totoroはarr、ループの反復ごとにこの値を再定義するだけの場合、最終的には、最終的な値は最後の配列要素に等しくなりますが、配列全体には等しくなりません
Oleg

@Oleg再定義が当てはまる場合、では何が異なるのですか?arr[]なぜarr[]再定義されないのですか?arr[]も文字列です。そして、どちらarrもテストしている間もarr[]、私の場合は再定義されませんでした。同じキーで値が異なるFormDataに複数の配列を取得しました。だから私はarr価値1と別のものarrを得ました2
トトロ

@トトロはい、そうです、私の間違い。これはサーバーサイド固有の質問だと思います。言語によって、クエリ文字列の解析方法が異なる場合があります。たとえば、PHPはあなたが説明したように動作しますがarr、配列でも機能する例(メモリがJavaの場合)を見ました。で、このトピックこの質問へのより詳細な答えがあります
オレグ

誰かがオブジェクトの配列を投稿しようとしている場合は、この回答を次のように拡張できますfor (var i = 0; i < myArr; i++) { var myItemInArr = myArr[i]; for (var prop in myItemInArr) { fileData.append(`myArr[${i}][${prop}]`, myItemInArr[prop]); } }
edqwerty

7

これは古い質問ですが、最近、ファイルと一緒にオブジェクトを投稿するときにこの問題に遭遇しました。オブジェクトと配列である子プロパティを使用して、オブジェクトを投稿できるようにする必要がありました。

以下の関数はオブジェクトをウォークスルーし、正しいformDataオブジェクトを作成します。

// formData - instance of FormData object
// data - object to post
function getFormData(formData, data, previousKey) {
  if (data instanceof Object) {
    Object.keys(data).forEach(key => {
      const value = data[key];
      if (value instanceof Object && !Array.isArray(value)) {
        return this.getFormData(formData, value, key);
      }
      if (previousKey) {
        key = `${previousKey}[${key}]`;
      }
      if (Array.isArray(value)) {
        value.forEach(val => {
          formData.append(`${key}[]`, val);
        });
      } else {
        formData.append(key, value);
      }
    });
  }
}

これは次のjsonを変換します-

{
  name: 'starwars',
  year: 1977,
  characters: {
    good: ['luke', 'leia'],
    bad: ['vader'],
  },
}

次のFormDataに

 name, starwars
 year, 1977
 characters[good][], luke
 characters[good][], leia
 characters[bad][], vader

それは私にとって便利でした、追加の内部の値に文字列(値)を適用する必要がありました(そうでなければtrue / falseで失敗します)。また、それはする必要があります(value !== null) && formData.append(key, value)だけではなくformData.append(key, value)、それ以外の場合は、NULL値に失敗した
アレクサンダー

7

Typescriptバージョン:

export class Utility {      
    public static convertModelToFormData(model: any, form: FormData = null, namespace = ''): FormData {
        let formData = form || new FormData();
        let formKey;

        for (let propertyName in model) {
            if (!model.hasOwnProperty(propertyName) || !model[propertyName]) continue;
            let formKey = namespace ? `${namespace}[${propertyName}]` : propertyName;
            if (model[propertyName] instanceof Date)
                formData.append(formKey, model[propertyName].toISOString());
            else if (model[propertyName] instanceof Array) {
                model[propertyName].forEach((element, index) => {
                    const tempFormKey = `${formKey}[${index}]`;
                    this.convertModelToFormData(element, formData, tempFormKey);
                });
            }
            else if (typeof model[propertyName] === 'object' && !(model[propertyName] instanceof File))
                this.convertModelToFormData(model[propertyName], formData, formKey);
            else
                formData.append(formKey, model[propertyName].toString());
        }
        return formData;
    }
}

使用:

let formData = Utility.convertModelToFormData(model);

素晴らしい仕事、超便利:D
Cosimo Chellini

2

すべてのタイプ入力をFormDataに追加する

const formData = new FormData();
for (let key in form) {
    Array.isArray(form[key])
        ? form[key].forEach(value => formData.append(key + '[]', value))
        : formData.append(key, form[key]) ;
}

2

ネストされたオブジェクトと配列がある場合、FormDataオブジェクトにデータを追加する最良の方法は再帰を使用することです。

function createFormData(formData, data, key) {
    if ( ( typeof data === 'object' && data !== null ) || Array.isArray(data) ) {
        for ( let i in data ) {
            if ( ( typeof data[i] === 'object' && data[i] !== null ) || Array.isArray(data[i]) ) {
                createFormData(formData, data[i], key + '[' + i + ']');
            } else {
                formData.append(key + '[' + i + ']', data[i]);
            }
        }
    } else {
        formData.append(key, data);
    }
}

1

単純な値の配列を含むモデルに有効な次のバージョン:

function convertModelToFormData(val, formData = new FormData(), namespace = '') {
    if((typeof val !== 'undefined') && (val !== null)) {
        if(val instanceof Date) {
            formData.append(namespace, val.toISOString());
        } else if(val instanceof Array) {
            for(let element of val) {
                convertModelToFormData(element, formData, namespace + '[]');
            }
        } else if(typeof val === 'object' && !(val instanceof File)) {
            for (let propertyName in val) {
                if(val.hasOwnProperty(propertyName)) {
                    convertModelToFormData(val[propertyName], formData, namespace ? namespace + '[' + propertyName + ']' : propertyName);
                }
            }
        } else {
            formData.append(namespace, val.toString());
        }
    }
    return formData;
}

1

@YackYの回答に基づいて、より短い再帰バージョン:

function createFormData(formData, key, data) {
    if (data === Object(data) || Array.isArray(data)) {
        for (var i in data) {
            createFormData(formData, key + '[' + i + ']', data[i]);
        }
    } else {
        formData.append(key, data);
    }
}

使用例:

var data = {a: '1', b: 2, c: {d: '3'}};
var formData = new FormData();
createFormData(formData, 'data', data);

送信されたデータ:

data[a]=1&
data[b]=2&
data[c][d]=3
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.