Ubah Objek JS menjadi data formulir

129

Bagaimana saya bisa mengonversi Objek JS saya menjadi FormData?

Alasan mengapa saya ingin melakukan ini adalah, saya memiliki objek yang saya buat dari nilai bidang formulir ~ 100.

var item = {
   description: 'Some Item',
   price : '0.00',
   srate : '0.00',
   color : 'red',
   ...
   ...
}

Sekarang saya diminta untuk menambahkan fungsionalitas file unggahan ke formulir saya yang, tentu saja tidak mungkin melalui JSON, jadi saya berencana untuk pindah ke FormData. Jadi, apakah ada cara agar saya dapat mengonversi objek JS saya FormData?

Kamran Ahmed
sumber
dapatkah Anda membagikan pekerjaan / kemajuan Anda?
Ritikesh
bagaimana dengan JSON.stringify ()?
Cerah Sharma
1
@Sunny - Itu akan menghasilkan teks JSON dalam sebuah string. Itu bukanlah sebuah FormDataobyek.
Quentin
Ya Anda bisa, Anda bisa menambahkan objek formData.
adeneo
dapatkah Anda menunjukkan kepada kami apa yang Anda maksud dengan FormData? format tertentu?
Sunny Sharma

Jawaban:

156

Jika Anda memiliki objek, Anda dapat dengan mudah membuat objek FormData dan menambahkan nama dan nilai dari objek tersebut ke formData.

Anda belum memposting kode apa pun, jadi ini adalah contoh umum;

var form_data = new FormData();

for ( var key in item ) {
    form_data.append(key, item[key]);
}

$.ajax({
    url         : 'http://example.com/upload.php',
    data        : form_data,
    processData : false,
    contentType : false,
    type: 'POST'
}).done(function(data){
    // do stuff
});

Ada lebih banyak contoh dalam dokumentasi di MDN

adeneo
sumber
4
@Lior - itemadalah objek biasa yang dibuat oleh OP, jadi seharusnya tidak memiliki properti yang bukan miliknya, kecuali seseorang membuat kesalahan dengan membuat prototipe sesuatu ke konstruktor Objek, dalam hal ini Anda akan berada dalam dunia yang bermasalah , dan itu bukanlah sesuatu yang harus kita lindungi.
adeneo
2
@Lior - ini hanya menambahkan pasangan kunci / nilai ke FormData, menambahkan properti prototipe tidak akan merusak apa pun, dan menggunakan Object.keysbukanlah jawabannya, karena Anda tidak harus mendapatkan kunci sebagai array, lalu mengulangi kunci untuk mendapatkannya nilai-nilai, Anda harus menggunakan for..inloop.
adeneo
2
Tentu saja, Anda tidak tahu apa yang diharapkan server ... karena ... di dalam JS adalah problamtic, solusinya tidak harus Object.keys (), bisa jadi hasOwnProperty (), tetapi setidaknya itu perlu peringatan.
Lior
3
@Lior - Jika server Anda rusak ketika menerima satu pasangan kunci / nilai lagi dalam permintaan POST, Anda salah melakukannya. Saya pikir jawabannya baik-baik saja, dan saya tidak akan mengubahnya untuk digunakan Object.keysatau hasOwnProperty()sebagai objek yang diposting dalam pertanyaan dan seharusnya tidak memerlukan semua itu. Alasan terkadang Anda melihat hasOwnPropertydigunakan di plugin, dll. Adalah karena Anda tidak pernah tahu apa yang mungkin dilakukan beberapa orang pada Objectkonstruktor, tetapi sebagian besar orang tidak perlu menguji properti yang diwariskan pada objek yang mereka buat, itu pertanda bahwa Anda mungkin melakukan sesuatu yang salah.
adeneo
5
@Lor, apakah Anda berniat membangun pesawat dari jerami selanjutnya, berharap itu akan menarik lebih banyak pesawat nyata yang akan menjatuhkan makanan dari langit? Penting untuk memahami mengapa cek hasOwnProperty digunakan, hanya mengatakan hal-hal yang dianggap "praktik terbaik" karena Anda membaca buku seseorang (menebak-nebak, Crockford) tidak membantu Anda terlalu jauh, mencoba mendidik sesama anggota So dengan lebih dari 100 kali reputasi dan 100 kali jumlah jawaban yang Anda miliki juga tidak banyak membantu maksud Anda. Juga, sebutkan satu lib pihak ketiga baru yang mengubah prototipe? Pos itu berasal dari waktu yang berbeda ...
Benjamin Gruenbaum
84

Dengan ES6 dan pendekatan pemrograman yang lebih fungsional, jawaban @ adeneo akan terlihat seperti ini:

function getFormData(object) {
    const formData = new FormData();
    Object.keys(object).forEach(key => formData.append(key, object[key]));
    return formData;
}

Dan sebagai alternatif menggunakan .reduce()dan fungsi panah:

getFormData = object => Object.keys(object).reduce((formData, key) => {
    formData.append(key, object[key]);
    return formData;
}, new FormData());
Jacob Lauritzen
sumber
45

Fungsi ini menambahkan semua data dari objek ke FormData

Versi ES6 dari @ developer033:

function buildFormData(formData, data, parentKey) {
  if (data && typeof data === 'object' && !(data instanceof Date) && !(data instanceof File)) {
    Object.keys(data).forEach(key => {
      buildFormData(formData, data[key], parentKey ? `${parentKey}[${key}]` : key);
    });
  } else {
    const value = data == null ? '' : data;

    formData.append(parentKey, value);
  }
}

function jsonToFormData(data) {
  const formData = new FormData();

  buildFormData(formData, data);

  return formData;
}

const my_data = {
  num: 1,
  falseBool: false,
  trueBool: true,
  empty: '',
  und: undefined,
  nullable: null,
  date: new Date(),
  name: 'str',
  another_object: {
    name: 'my_name',
    value: 'whatever'
  },
  array: [
    {
      key1: {
        name: 'key1'
      }
    }
  ]
};

jsonToFormData(my_data)

versi jQuery:

function appendFormdata(FormData, data, name){
    name = name || '';
    if (typeof data === 'object'){
        $.each(data, function(index, value){
            if (name == ''){
                appendFormdata(FormData, value, index);
            } else {
                appendFormdata(FormData, value, name + '['+index+']');
            }
        })
    } else {
        FormData.append(name, data);
    }
}


var formData = new FormData(),
    your_object = {
        name: 'test object',
        another_object: {
            name: 'and other objects',
            value: 'whatever'
        }
    };
appendFormdata(formData, your_object);
Vladimir Novopashin
sumber
Bagus Teruskan
Vivek Doshi
Bekerja dengan sangat baik! Terima kasih! Saya juga harus menambahkan && !(data instanceof Blob)dalam kasus saya untuk mengunggah gambar saya
Clément Baconnier
Berfungsi dengan baik untuk saya, saya menambahkan if (typeof data === 'object' && data! == null) {karena itu membuat pengecualian jika nilainya null
al000y
Untuk versi ES6, saya menambahkan && !(Array.isArray(data) && !data.length)kondisi "jika", atau array kosong akan dihapus.
Mtxz
Ini jenius. Memecahkan masalah saya dengan sangat indah.
dearsina
15

Jawaban lainnya tidak lengkap bagi saya. Saya mulai dari jawaban Vladimir Novopashin dan memodifikasinya. Inilah hal-hal yang saya butuhkan dan bug yang saya temukan:

  • Dukungan untuk file
  • Dukungan untuk array
  • Bug: File di dalam objek kompleks perlu ditambahkan, .propbukan [prop]. Misalnya, formData.append('photos[0][file]', file)tidak berfungsi di google chrome, saat formData.append('photos[0].file', file)bekerja
  • Abaikan beberapa properti di objek saya

Kode berikut harus berfungsi di IE11 dan browser evergreen.

function objectToFormData(obj, rootName, ignoreList) {
    var formData = new FormData();

    function appendFormData(data, root) {
        if (!ignore(root)) {
            root = root || '';
            if (data instanceof File) {
                formData.append(root, data);
            } else if (Array.isArray(data)) {
                for (var i = 0; i < data.length; i++) {
                    appendFormData(data[i], root + '[' + i + ']');
                }
            } else if (typeof data === 'object' && data) {
                for (var key in data) {
                    if (data.hasOwnProperty(key)) {
                        if (root === '') {
                            appendFormData(data[key], key);
                        } else {
                            appendFormData(data[key], root + '.' + key);
                        }
                    }
                }
            } else {
                if (data !== null && typeof data !== 'undefined') {
                    formData.append(root, data);
                }
            }
        }
    }

    function ignore(root){
        return Array.isArray(ignoreList)
            && ignoreList.some(function(x) { return x === root; });
    }

    appendFormData(obj, rootName);

    return formData;
}
Gudradain
sumber
2
Satu-satunya jawaban yang mendukung array, objek dan file.
sotn
Hai, mengapa Anda menambahkan File ke root? Apakah mungkin untuk menambahkannya ke anak juga?
Cedric Arnould
@CedricArnould Ini mungkin kesalahpahaman tetapi metodenya rekursif jadi meskipun itu ditulis formData.append(root, data), itu tidak berarti itu ditambahkan ke root.
Gudradain
Saya mengerti jawaban Anda, anehnya ketika saya mendapatkan hasilnya di server, saya memiliki Kumpulan File dan datanya yang unik. Tapi saya bisa melihat di File nama memberikan informasi kepada anak mana yang terhubung. Mungkin masalahnya berasal dari .Net Core dan cara mengelola file unggahan. Terima kasih atas jawaban anda.
Cedric Arnould
Saya mencoba menggunakan ini tetapi tidak ada contoh penggunaan. format yang diharapkan dari parameter ignoreList akan sangat membantu.
jpro
9

Coba fungsi JSON.stringify seperti di bawah ini

var postData = JSON.stringify(item);
var formData = new FormData();
formData.append("postData",postData );
Udayraj Khuman
sumber
1
Ini adalah cara terbaik untuk mencapai ini.
Rob
tetap menambahkan json setelah beberapa kali error debug
Snow Bases
7

Saya memiliki skenario di mana JSON bersarang harus diserialkan secara linier sementara data formulir dibuat, karena ini adalah cara server mengharapkan nilai. Jadi, saya menulis fungsi rekursif kecil yang menerjemahkan JSON seperti ini:

{
   "orderPrice":"11",
   "cardNumber":"************1234",
   "id":"8796191359018",
   "accountHolderName":"Raj Pawan",
   "expiryMonth":"02",
   "expiryYear":"2019",
   "issueNumber":null,
   "billingAddress":{
      "city":"Wonderland",
      "code":"8796682911767",
      "firstname":"Raj Pawan",
      "lastname":"Gumdal",
      "line1":"Addr Line 1",
      "line2":null,
      "state":"US-AS",
      "region":{
         "isocode":"US-AS"
      },
      "zip":"76767-6776"
   }
}

Menjadi seperti ini:

{
   "orderPrice":"11",
   "cardNumber":"************1234",
   "id":"8796191359018",
   "accountHolderName":"Raj Pawan",
   "expiryMonth":"02",
   "expiryYear":"2019",
   "issueNumber":null,
   "billingAddress.city":"Wonderland",
   "billingAddress.code":"8796682911767",
   "billingAddress.firstname":"Raj Pawan",
   "billingAddress.lastname":"Gumdal",
   "billingAddress.line1":"Addr Line 1",
   "billingAddress.line2":null,
   "billingAddress.state":"US-AS",
   "billingAddress.region.isocode":"US-AS",
   "billingAddress.zip":"76767-6776"
}

Server akan menerima data formulir yang dalam format yang dikonversi ini.

Berikut fungsinya:

function jsonToFormData (inJSON, inTestJSON, inFormData, parentKey) {
    // http://stackoverflow.com/a/22783314/260665
    // Raj: Converts any nested JSON to formData.
    var form_data = inFormData || new FormData();
    var testJSON = inTestJSON || {};
    for ( var key in inJSON ) {
        // 1. If it is a recursion, then key has to be constructed like "parent.child" where parent JSON contains a child JSON
        // 2. Perform append data only if the value for key is not a JSON, recurse otherwise!
        var constructedKey = key;
        if (parentKey) {
            constructedKey = parentKey + "." + key;
        }

        var value = inJSON[key];
        if (value && value.constructor === {}.constructor) {
            // This is a JSON, we now need to recurse!
            jsonToFormData (value, testJSON, form_data, constructedKey);
        } else {
            form_data.append(constructedKey, inJSON[key]);
            testJSON[constructedKey] = inJSON[key];
        }
    }
    return form_data;
}

Doa:

        var testJSON = {};
        var form_data = jsonToFormData (jsonForPost, testJSON);

Saya menggunakan testJSON hanya untuk melihat hasil yang dikonversi karena saya tidak dapat mengekstrak konten form_data. Panggilan pos AJAX:

        $.ajax({
            type: "POST",
            url: somePostURL,
            data: form_data,
            processData : false,
            contentType : false,
            success: function (data) {
            },
            error: function (e) {
            }
        });
Raj Pawan Gumdal
sumber
Hai Raj, bagaimana dengan array? Misalnya Anda memiliki lebih dari 1 alamat penagihan. Bagaimana Anda memperbaikinya?
Sam
1
Saya telah menemukan jawabannya! Posting Anda sangat membantu. Terima kasih!
Sam
3

Maaf untuk jawaban yang terlambat, tetapi saya kesulitan dengan ini karena Angular 2 saat ini tidak mendukung pengunggahan file. Jadi, cara melakukannya adalah dengan mengirimkan XMLHttpRequestwith FormData. Jadi, saya membuat fungsi untuk melakukannya. Saya menggunakan Ketikan . Untuk mengubahnya menjadi Javascript cukup hapus deklarasi tipe data.

/**
     * Transforms the json data into form data.
     *
     * Example:
     *
     * Input:
     * 
     * fd = new FormData();
     * dob = {
     *  name: 'phone',
     *  photos: ['myphoto.jpg', 'myotherphoto.png'],
     *  price: '615.99',
     *  color: {
     *      front: 'red',
     *      back: 'blue'
     *  },
     *  buttons: ['power', 'volup', 'voldown'],
     *  cameras: [{
     *      name: 'front',
     *      res: '5Mpx'
     *  },{
     *      name: 'back',
     *      res: '10Mpx'
     *  }]
     * };
     * Say we want to replace 'myotherphoto.png'. We'll have this 'fob'.
     * fob = {
     *  photos: [null, <File object>]
     * };
     * Say we want to wrap the object (Rails way):
     * p = 'product';
     *
     * Output:
     *
     * 'fd' object updated. Now it will have these key-values "<key>, <value>":
     *
     * product[name], phone
     * product[photos][], myphoto.jpg
     * product[photos][], <File object>
     * product[color][front], red
     * product[color][back], blue
     * product[buttons][], power
     * product[buttons][], volup
     * product[buttons][], voldown
     * product[cameras][][name], front
     * product[cameras][][res], 5Mpx
     * product[cameras][][name], back
     * product[cameras][][res], 10Mpx
     * 
     * @param {FormData}  fd  FormData object where items will be appended to.
     * @param {Object}    dob Data object where items will be read from.
     * @param {Object =   null} fob File object where items will override dob's.
     * @param {string =   ''} p Prefix. Useful for wrapping objects and necessary for internal use (as this is a recursive method).
     */
    append(fd: FormData, dob: Object, fob: Object = null, p: string = ''){
        let apnd = this.append;

        function isObj(dob, fob, p){
            if(typeof dob == "object"){
                if(!!dob && dob.constructor === Array){
                    p += '[]';
                    for(let i = 0; i < dob.length; i++){
                        let aux_fob = !!fob ? fob[i] : fob;
                        isObj(dob[i], aux_fob, p);
                    }
                } else {
                    apnd(fd, dob, fob, p);
                }
            } else {
                let value = !!fob ? fob : dob;
                fd.append(p, value);
            }
        }

        for(let prop in dob){
            let aux_p = p == '' ? prop : `${p}[${prop}]`;
            let aux_fob = !!fob ? fob[prop] : fob;
            isObj(dob[prop], aux_fob, aux_p);
        }
    }
Aleksandrus
sumber
Anda harus menyertakan indeks larik alih-alih []untuk properti objek di dalam larik numerik agar tetap utuh
Vicary
1

Versi TypeScript:

static convertModelToFormData(model: any, form: FormData = null, namespace = ''): FormData {
    let formData = form || new FormData();
    for (let propertyName in model) {
      if (!model.hasOwnProperty(propertyName) || model[propertyName] == undefined) continue;
      let formKey = namespace ? `${namespace}[${propertyName}]` : propertyName;
      if (model[propertyName] instanceof Date) {        
        formData.append(formKey, this.dateTimeToString(model[propertyName]));
      }
      else if (model[propertyName] instanceof Array) {
        model[propertyName].forEach((element, index) => {
          if (typeof element != 'object')
            formData.append(`${formKey}[]`, element);
          else {
            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;
  }

https://gist.github.com/Mds92/091828ea857cc556db2ca0f991fee9f6

Mohammad Dayyan
sumber
1
Pertama-tama, namespaceadalah kata kunci yang dipesan di TypeScript( typescriptlang.org/docs/handbook/namespaces.html dan github.com/Microsoft/TypeScript/issues/… ). Juga, tampaknya Anda lupa berurusan Filesejak surat elsewasiat terakhir append "[object File]"ke formData.
Jyrkka
1

Anda cukup menginstal qs:

npm i qs

Cukup impor:

import qs from 'qs'

Berikan objek ke qs.stringify():

var item = {
   description: 'Some Item',
   price : '0.00',
   srate : '0.00',
   color : 'red',
   ...
   ...
}

qs.stringify(item)
Balaj Khan
sumber
1

Secara rekursif

const toFormData = (f => f(f))(h => f => f(x => h(h)(f)(x)))(f => fd => pk => d => {
  if (d instanceof Object) {
    Object.keys(d).forEach(k => {
      const v = d[k]
      if (pk) k = `${pk}[${k}]`
      if (v instanceof Object && !(v instanceof Date) && !(v instanceof File)) {
        return f(fd)(k)(v)
      } else {
        fd.append(k, v)
      }
    })
  }
  return fd
})(new FormData())()

let data = {
  name: 'John',
  age: 30,
  colors: ['red', 'green', 'blue'],
  children: [
    { name: 'Max', age: 3 },
    { name: 'Madonna', age: 10 }
  ]
}
console.log('data', data)
document.getElementById("data").insertAdjacentHTML('beforeend', JSON.stringify(data))

let formData = toFormData(data)

for (let key of formData.keys()) {
  console.log(key, formData.getAll(key).join(','))
  document.getElementById("item").insertAdjacentHTML('beforeend', `<li>${key} = ${formData.getAll(key).join(',')}</li>`)
}
<p id="data"></p>
<ul id="item"></ul>

vmartins
sumber
jawaban terbaik imho
ling
0

Metode ini mengonversi objek JS menjadi FormData:

function convertToFormData(params) {
    return Object.entries(params)
        .reduce((acc, [key, value]) => {
            if (Array.isArray(value)) {
                value.forEach((v, k) => acc.append(`${key}[${k}]`, value));
            } else if (typeof value === 'object' && !(value instanceof File) && !(value instanceof Date)) {
                Object.entries(value).forEach((v, k) => acc.append(`${key}[${k}]`, value));
            } else {
                acc.append(key, value);
            }

            return acc;
        }, new FormData());
}

Biksu Monyet
sumber
Perbaiki saja iterasi entri objek bersarang panggilan: Object.entries(value).forEach((v, k) => acc.append(`${key}[${v[0]}]`, v[1]));
heber gentilin
0

Dalam kasus saya, objek saya juga memiliki properti yang berupa array file. Karena mereka biner, mereka harus ditangani secara berbeda - indeks tidak perlu menjadi bagian dari kunci. Jadi saya mengubah jawaban @Vladimir Novopashin dan @ developer033:

export function convertToFormData(data, formData, parentKey) {
  if(data === null || data === undefined) return null;

  formData = formData || new FormData();

  if (typeof data === 'object' && !(data instanceof Date) && !(data instanceof File)) {
    Object.keys(data).forEach(key => 
      convertToFormData(data[key], formData, (!parentKey ? key : (data[key] instanceof File ? parentKey : `${parentKey}[${key}]`)))
    );
  } else {
    formData.append(parentKey, data);
  }

  return formData;
}
Elnoor
sumber
0

Saya menggunakan ini untuk Posting data objek saya sebagai Data Formulir.

const encodeData = require('querystring');

const object = {type: 'Authorization', username: 'test', password: '123456'};

console.log(object);
console.log(encodeData.stringify(object));
Yunus ER
sumber
0

Mungkin Anda sedang mencari ini, kode yang menerima objek javascript Anda, buat objek FormData darinya dan kemudian POST ke server Anda menggunakan Fetch API baru :

    let myJsObj = {'someIndex': 'a value'};

    let datos = new FormData();
    for (let i in myJsObj){
        datos.append( i, myJsObj[i] );
    }

    fetch('your.php', {
        method: 'POST',
        body: datos
    }).then(response => response.json())
        .then(objson => {
            console.log('Success:', objson);
        })
        .catch((error) => {
            console.error('Error:', error);
        });
Oswaldo Rodriguez Gonzalez
sumber
0

Saya mereferensikan ini dari jawaban Gudradain . Saya mengeditnya sedikit dalam format Ketikan.

class UtilityService {
    private appendFormData(formData, data, rootName) {

        let root = rootName || '';
        if (data instanceof File) {
            formData.append(root, data);
        } else if (Array.isArray(data)) {
            for (var i = 0; i < data.length; i++) {
                this.appendFormData(formData, data[i], root + '[' + i + ']');
            }
        } else if (typeof data === 'object' && data) {
            for (var key in data) {
                if (data.hasOwnProperty(key)) {
                    if (root === '') {
                        this.appendFormData(formData, data[key], key);
                    } else {
                        this.appendFormData(formData, data[key], root + '.' + key);
                    }
                }
            }
        } else {
            if (data !== null && typeof data !== 'undefined') {
                formData.append(root, data);
            }
        }
    }

    getFormDataFromObj(data) {
        var formData = new FormData();

        this.appendFormData(formData, data, '');

        return formData;
    }
}

export let UtilityMan = new UtilityService();
Mikhael Pramodana
sumber
0

Saya mungkin sedikit terlambat ke pesta tetapi inilah yang saya buat untuk mengonversi objek tunggal ke FormData.

function formData(formData, filesIgnore = []) {
  let data = new FormData();

  let files = filesIgnore;

  Object.entries(formData).forEach(([key, value]) => {
    if (typeof value === 'object' && !files.includes(key)) {
      data.append(key, JSON.stringify(value) || null);
    } else if (files.includes(key)) {
      data.append(key, value[0] || null);
    } else {
      data.append(key, value || null);
    }
  })

  return data;
}

Bagaimana cara kerjanya? Ini akan mengubah dan mengembalikan semua properti mengharapkan objek File yang telah Anda setel dalam daftar abaikan (argumen ke-2. Jika ada yang bisa memberi tahu saya cara yang lebih baik untuk menentukan ini yang akan membantu!) Ke dalam string json menggunakan JSON.stringify. Kemudian di server Anda, Anda hanya perlu mengubahnya kembali menjadi objek JSON.

Contoh:

let form = {
  first_name: 'John',
  last_name: 'Doe',
  details: {
    phone_number: 1234 5678 910,
    address: '123 Some Street',
  },
  profile_picture: [object FileList] // set by your form file input. Currently only support 1 file per property.
}

function submit() {
  let data = formData(form, ['profile_picture']);

  axios.post('/url', data).then(res => {
    console.log('object uploaded');
  })
}

Saya masih agak baru dalam permintaan Http dan JavaScript sehingga setiap umpan balik akan sangat dihargai!

Gibbu
sumber