menambahkan array ke FormData dan mengirim melalui AJAX

109

Saya menggunakan ajax untuk mengirimkan formulir multi bagian dengan larik, bidang teks, dan file.

Saya menambahkan setiap VAR ke data utama seperti itu

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

kemudian saya menggunakan fungsi ajax untuk mengirimkannya ke file PHP untuk disimpan di dalam sql DB.

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

Namun di sisi PHP, arrvariabel berupa array muncul sebagai string.

Ketika saya tidak mengirimnya dengan ajax sebagai data Formulir tetapi menggunakan $.POSTopsi sederhana, saya mendapatkannya sebagai array di sisi PHP, tetapi kemudian saya tidak dapat mengirim file juga.

ada solusi?

shultz
sumber

Jawaban:

93

Anda memiliki beberapa opsi:

Konversikan menjadi string JSON, lalu parse dalam PHP (disarankan)

JS

var json_arr = JSON.stringify(arr);

PHP

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

Atau gunakan metode @ Curios

Mengirim array melalui FormData.


Tidak disarankan: Menyerialkan data dengan, kemudian deserialisasi dalam PHP

JS

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

PHP

$arr = explode("<#>", $_POST['arr']);
Richard de Wit
sumber
1
masalahnya adalah bahwa array berisi baris teks NYATA, dengan spasi dan tanda baca. Saya tidak ingin mengacaukannya.
shultz
3
Saat Anda mengenkode dan menguraikannya dengan JSON, data tidak akan hilang. Cobalah;)
Richard de Wit
Jika Anda menggunakan asp.net dengan pemetaan otomatis atau yang serupa, jawaban @Curious adalah yang Anda butuhkan.
Martín Coll
1
@Richard de Wit Jika Anda memiliki data seperti File atau FormData, Anda akan kehilangannya di json.stringfy
Mohsen
Saya suka merangkai lebih baik, lebih sederhana. Karena Anda perlu melakukan semacam rekursi untuk melewatkan array array menggunakan [] tetapi perlu diketahui bahwa itu bisa dilakukan dengan cara itu.
Chopnut
260

Anda juga dapat mengirim array melalui FormDatacara ini:

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

Jadi Anda bisa menulis arr[]dengan cara yang sama seperti Anda melakukannya dengan formulir HTML sederhana. Dalam kasus PHP itu harus berfungsi.

Anda mungkin menemukan artikel ini berguna: Bagaimana cara melewatkan array dalam string kueri?

Oleg
sumber
1
@Oleg Apa perlunya untuk menulis arr[]di formData.append('arr[]', arr[i]);? kenapa tidak arrbenar? Saya mencoba keduanya tetapi hanya arr[]berhasil.
Totoro
@Totoro karena jika arrAnda baru saja mendefinisikan ulang nilai ini pada setiap iterasi loop, dan pada akhirnya, nilai akhir akan sama dengan elemen array terakhir, tetapi tidak keseluruhan array
Oleg
@Oleg Jika definisi ulang adalah kasusnya, lalu apa yang berbeda arr[], mengapa tidak arr[]didefinisikan ulang? arr[]juga sebuah string. Dan sementara pengujian baik tidak arrjuga arr[]didefinisikan kembali dalam kasus saya. Saya mendapat beberapa array di FormData dengan kunci yang sama tetapi nilai berbeda. Jadi saya mendapat arrnilai 1dan satu lagi arrdengan nilai 2.
Totoro
@Totoro ya, kamu benar, kesalahanku. Saya yakin ini adalah pertanyaan yang lebih spesifik di sisi server. Bahasa yang berbeda dapat mengurai string kueri secara berbeda. Misalnya, PHP berperilaku seperti yang Anda jelaskan, tetapi saya melihat contoh (jika memori berfungsi, di Java), di mana arrjuga bekerja untuk array. Dalam topik ini ada jawaban yang lebih detail untuk pertanyaan ini
Oleg
Jika ada yang ingin memposting array objek, Anda dapat memperluas jawaban ini sebagai berikutfor (var i = 0; i < myArr; i++) { var myItemInArr = myArr[i]; for (var prop in myItemInArr) { fileData.append(`myArr[${i}][${prop}]`, myItemInArr[prop]); } }
edqwerty
7

Ini adalah pertanyaan lama tetapi saya mengalami masalah ini dengan memposting objek bersama dengan file baru-baru ini. Saya harus bisa memposting sebuah objek, dengan properti anak yang merupakan objek dan array juga.

Fungsi di bawah ini akan berjalan melalui sebuah objek dan membuat objek formData yang benar.

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

Ini akan mengubah json berikut -

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

ke dalam FormData berikut

 name, starwars
 year, 1977
 characters[good][], luke
 characters[good][], leia
 characters[bad][], vader
VtoCorleone
sumber
Itu berguna bagi saya, hanya harus menerapkan String (nilai) pada nilai di dalam menambahkan (jika tidak gagal untuk benar / salah). Juga seharusnya (value !== null) && formData.append(key, value)bukan hanya formData.append(key, value)sebaliknya itu gagal pada nilai nol
Alexander
7

Versi naskah ketikan:

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

Menggunakan:

let formData = Utility.convertModelToFormData(model);
Mohammad Dayyan
sumber
Kerja bagus, sangat berguna: D
Cosimo Chellini
3

tambahkan semua jenis input ke 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]) ;
}
HamidNE
sumber
2

Jika Anda memiliki objek dan larik bersarang, cara terbaik untuk mengisi objek FormData adalah menggunakan rekursi.

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);
    }
}
YackY
sumber
1

Versi berikutnya valid untuk model yang berisi larik nilai sederhana:

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;
}
Megabyte
sumber
1

Berdasarkan jawaban @YackY versi rekursi yang lebih pendek:

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

Contoh penggunaan:

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

Data terkirim:

data[a]=1&
data[b]=2&
data[c][d]=3
dikirill
sumber