Cara mengonversi FormData (Objek HTML5) ke JSON

112

Bagaimana cara mengonversi objek HTML5 FormData ke JSON? Tanpa Jquery dan menangani properti bersarang di FormData seperti objek.

Leonardo Villela
sumber
2
Apa yang sedang Anda coba lakukan? Apakah JSON.stringify()membantu? Mungkin Anda mencoba memperbaiki sesuatu yang mungkin dilakukan dengan cara lain?
Justinas
Kemungkinan duplikat objek Konversi JS ke string JSON
Liam
4
Bukan duplikat karena saya tidak ingin mengonversi objek javascript menjadi json, saya juga tidak ingin menggunakan Jquery.serialize ()
Leonardo Villela
periksa ini: stackoverflow.com/a/39248551/6293856
Bhavik Hirani

Jawaban:

158

Anda juga bisa menggunakan forEachpada FormDataobjek langsung:

var object = {};
formData.forEach(function(value, key){
    object[key] = value;
});
var json = JSON.stringify(object);

MEMPERBARUI:

Dan bagi mereka yang lebih memilih solusi yang sama dengan fungsi panah ES6 :

var object = {};
formData.forEach((value, key) => object[key] = value);
var json = JSON.stringify(object);

PEMBARUAN 2:

Dan bagi mereka yang menginginkan dukungan untuk daftar pilihan ganda atau elemen formulir lainnya dengan banyak nilai (karena ada begitu banyak komentar di bawah jawaban mengenai masalah ini, saya akan menambahkan solusi yang mungkin) :

var object = {};
formData.forEach((value, key) => {
    // Reflect.has in favor of: object.hasOwnProperty(key)
    if(!Reflect.has(object, key)){
        object[key] = value;
        return;
    }
    if(!Array.isArray(object[key])){
        object[key] = [object[key]];    
    }
    object[key].push(value);
});
var json = JSON.stringify(object);

Di sini Fiddle mendemonstrasikan penggunaan metode ini dengan daftar pilih multi sederhana.

PEMBARUAN 3:

Sebagai catatan tambahan bagi mereka yang berakhir di sini, jika tujuan mengonversi data formulir ke json adalah mengirimnya melalui permintaan HTTP XML ke server, Anda dapat mengirim FormDataobjek secara langsung tanpa mengubahnya. Sesederhana ini:

var request = new XMLHttpRequest();
request.open("POST", "http://example.com/submitform.php");
request.send(formData);

Lihat juga Menggunakan Objek FormData di MDN untuk referensi :

UPDATE 4:

Seperti disebutkan dalam salah satu komentar di bawah jawaban saya, stringifymetode JSON tidak akan berfungsi di luar kotak untuk semua jenis objek. Untuk informasi lebih lanjut tentang jenis apa yang didukung, saya ingin merujuk ke bagian Deskripsi di dokumentasi MDNJSON.stringify .

Dalam uraian tersebut juga disebutkan bahwa:

Jika nilai memiliki metode toJSON (), itu bertanggung jawab untuk menentukan data apa yang akan diserialkan.

Ini berarti Anda dapat menyediakan toJSONmetode serialisasi Anda sendiri dengan logika untuk membuat serialisasi objek kustom Anda. Dengan demikian, Anda dapat dengan cepat dan mudah membangun dukungan serialisasi untuk hierarki objek yang lebih kompleks.

Melayu
sumber
1
Seperti yang disebutkan dalam jawaban dari @TomasPrado, pastikan Anda tidak memerlukan dukungan untuk IE11.
Layu
4
Ini tidak berfungsi dengan beberapa elemen bentuk pilihan karena mereka berbagi kunci yang sama Anda akhirnya menimpa nilai yang hanya mengembalikan elemen yang dipilih terakhir
Sean
1
@ Sean Saya memberikan jawaban yang berfungsi dengan beberapa nilai untuk <SELECT MULTIPLE>dan <INPUT type="checkbox">dengan nama yang sama, dengan mengubah nilai menjadi array.
beberapa
formData bukan seri. bagaimana Anda bisa mengulang? menerima jawaban tetapi ada sesuatu yang terlewat.
Nuri YILMAZ
4
Kecuali jika perlu banyak pilihan dll .. jawabannya JSON.stringify(Object.fromEntries(formData));jauh lebih baik
Tom Stickel
112

Pada 2019, tugas semacam ini menjadi sangat mudah.

JSON.stringify(Object.fromEntries(formData));

Object.fromEntries: Didukung di Chrome 73+, Firefox 63+, Safari 12.1

hakatashi
sumber
2
Datang ke sini untuk memposting ini, senang melihat utas ini dan melihat bagaimana jawaban telah berkembang selama bertahun-tahun
Marcin
14
Ini sepertinya tidak berfungsi dengan benar pada formulir yang memiliki beberapa bidang dengan nama yang sama.
JukkaP
3
Ini adalah tahun 2020 dan ini tidak menangani beberapa nilai yang dipilih dari <select multiple>atau <input type="checkbox"> 😞
beberapa
4
Lebih baik menggunakan formData.entries:JSON.stringify(Object.fromEntries(formData.entries()));
Kohver
22

Berikut adalah cara melakukannya dengan gaya yang lebih fungsional, tanpa menggunakan perpustakaan.

Array.from(formData.entries()).reduce((memo, pair) => ({
  ...memo,
  [pair[0]]: pair[1],
}), {});

Contoh:

document.getElementById('foobar').addEventListener('submit', (e) => {
  e.preventDefault();

  const formData = new FormData(e.target);
  const data = Array.from(formData.entries()).reduce((memo, pair) => ({
    ...memo,
    [pair[0]]: pair[1],
  }), {});
  document.getElementById('output').innerHTML = JSON.stringify(data);
});
<form id='foobar'>
  <input name='baz' />
  <input type='submit' />
</form>

<pre id='output'>Input some value and submit</pre>

dzuc
sumber
1
Jawaban terbaik disini. Terima kasih :)
Chunky Chunk
4
Saya sangat suka jawaban ini tetapi masih tidak menangani banyak item. Saya memposting jawaban baru berdasarkan ini untuk menangani kasus-kasus itu.
CarlosH.
10

Jika Anda memiliki banyak entri dengan nama yang sama, misalnya jika Anda menggunakan <SELECT multiple>atau memiliki banyak entri dengan nama <INPUT type="checkbox">yang sama, Anda perlu menjaganya dan membuat array nilainya. Jika tidak, Anda hanya mendapatkan nilai yang terakhir dipilih.

Berikut adalah varian ES6 modern:

function formToJSON( elem ) {
  let output = {};
  new FormData( elem ).forEach(
    ( value, key ) => {
      // Check if property already exist
      if ( Object.prototype.hasOwnProperty.call( output, key ) ) {
        let current = output[ key ];
        if ( !Array.isArray( current ) ) {
          // If it's not an array, convert it to an array.
          current = output[ key ] = [ current ];
        }
        current.push( value ); // Add the new value to the array.
      } else {
        output[ key ] = value;
      }
    }
  );
  return JSON.stringify( output );
}

Kode yang sedikit lebih lama (tetapi masih tidak didukung oleh IE11, karena tidak mendukung ForEachatau entriesaktif FormData)

function formToJSON( elem ) {
  var current, entries, item, key, output, value;
  output = {};
  entries = new FormData( elem ).entries();
  // Iterate over values, and assign to item.
  while ( item = entries.next().value )
    {
      // assign to variables to make the code more readable.
      key = item[0];
      value = item[1];
      // Check if key already exist
      if (Object.prototype.hasOwnProperty.call( output, key)) {
        current = output[ key ];
        if ( !Array.isArray( current ) ) {
          // If it's not an array, convert it to an array.
          current = output[ key ] = [ current ];
        }
        current.push( value ); // Add the new value to the array.
      } else {
        output[ key ] = value;
      }
    }
    return JSON.stringify( output );
  }
beberapa
sumber
7

Anda bisa mencapai ini dengan menggunakan objek FormData () . Objek FormData ini akan diisi dengan kunci / nilai formulir saat ini menggunakan properti nama setiap elemen untuk kunci dan nilai yang dikirimkan untuk nilai tersebut. Ini juga akan menyandikan konten masukan file.

Contoh:

var myForm = document.getElementById('myForm');
myForm.addEventListener('submit', function(event)
{
    event.preventDefault();
    var formData = new FormData(myForm),
        result = {};

    for (var entry of formData.entries())
    {
        result[entry[0]] = entry[1];
    }
    result = JSON.stringify(result)
    console.log(result);

});
GiriB
sumber
Ini tidak menghasilkan json
Liam
1
@Liam Sudahkah Anda mencoba ini dengan elemen bentuk? Dan beri tahu saya mengapa itu tidak menghasilkan objek JSON?
GiriB
1
Tidak ada yang namanya objek json. Json adalah notasi string
Liam
1
@Liam Setelah objek dibuat, mereka dapat menggunakan JSON.stringify (result). Dan saya telah mengedit jawaban saya. Tolong diperiksa. Dan menarik suara down.
GiriB
1
Anda juga dapat membuat pernyataan untuk lebih ekspresif jika Anda menggunakan ES6: for (const [key, value] of formData.entries())
Teddy Zetterlund
7

Fungsi Mudah Digunakan

Saya Telah Menciptakan Fungsi Untuk Ini

function FormDataToJSON(FormElement){    
    var formData = new FormData(FormElement);
    var ConvertedJSON= {};
    for (const [key, value]  of formData.entries())
    {
        ConvertedJSON[key] = value;
    }

    return ConvertedJSON
}

Contoh Penggunaan

var ReceivedJSON = FormDataToJSON(document.getElementById('FormId');)

Dalam kode ini saya telah membuat variabel JSON kosong menggunakan forloop yang telah saya gunakan keydari Objek formData ke Kunci JSON di setiap Itration.

Anda Menemukan Kode Ini Di Perpustakaan JS Saya Di GitHub Sarankan Saya Jika Perlu Perbaikan, Saya Telah Menempatkan Kode Di Sini https://github.com/alijamal14/Utilities/blob/master/Utilities.js

Ali Jamal
sumber
1
@zuluk Dijelaskan Terima Kasih
Ali Jamal
Ini tidak menangani beberapa nilai yang dipilih dari <select multiple>atau <input type="checkbox">.
beberapa
5

Postingan ini sudah berumur setahun ... tapi, saya sangat, sangat suka jawaban ES6 @dzuc. Namun ini tidak lengkap karena tidak dapat menangani beberapa kotak centang atau kotak centang. Ini telah menunjuk dan solusi kode telah ditawarkan. Saya merasa mereka berat dan tidak dioptimalkan. Jadi saya menulis 2 versi berdasarkan @dzuc untuk menangani kasus ini:

  • Untuk bentuk gaya ASP di mana beberapa nama item bisa diulangi dengan sederhana.
let r=Array.from(fd).reduce(
  (o , [k,v]) => (
     (!o[k])
     ? {...o , [k] : v}
     : {...o , [k] : [...o[k] , v]}
   )
   ,{}
);
let obj=JSON.stringify(r);

Versi Jagoan satu baris:

Array.from(fd).reduce((o,[k,v])=>((!o[k])?{...o,[k]:v}:{...o,[k]:[...o[k],v]}),{});
  • Untuk bentuk gaya PHP di mana beberapa nama item harus memiliki []akhiran.
let r=Array.from(fd).reduce(
  (o , [k,v]) => (
    (k.split('[').length>1)
    ? (k=k.split('[')[0]
      , (!o[k])
      ? {...o , [k] : [v]}
      : {...o , [k] : [...o[k] , v ]}
    )
    : {...o , [k] : v}
  )
  ,{}
);
let obj=JSON.stringify(r);

Versi Jagoan satu baris:

Array.from(fd).reduce((o,[k,v])=>((k.split('[').length>1)?(k=k.split('[')[0],(!o[k])?{...o,[k]:[v]}:{...o,[k]:[...o[k],v]}):{...o,[k]:v}),{});
  • Perpanjangan bentuk PHP yang mendukung array multi-level.

Sejak terakhir kali saya menulis kasus kedua sebelumnya, di tempat kerja muncul kasus bahwa formulir PHP memiliki kotak centang pada multi-level. Saya menulis kasus baru untuk mendukung kasus sebelumnya dan yang ini. Saya membuat cuplikan untuk memamerkan kasus ini dengan lebih baik, hasilnya ditampilkan di konsol untuk demo ini, ubah ini sesuai kebutuhan Anda. Mencoba mengoptimalkannya sebaik mungkin tanpa mengorbankan kinerja, namun, ini membahayakan beberapa keterbacaan manusia. Ini mengambil keuntungan bahwa array adalah objek dan variabel yang menunjuk ke array disimpan sebagai referensi. Tidak ada jagoan untuk yang satu ini, jadilah tamuku.

let nosubmit = (e) => {
  e.preventDefault();
  const f = Array.from(new FormData(e.target));
  const obj = f.reduce((o, [k, v]) => {
    let a = v,
      b, i,
      m = k.split('['),
      n = m[0],
      l = m.length;
    if (l > 1) {
      a = b = o[n] || [];
      for (i = 1; i < l; i++) {
        m[i] = (m[i].split(']')[0] || b.length) * 1;
        b = b[m[i]] = ((i + 1) == l) ? v : b[m[i]] || [];
      }
    }
    return { ...o, [n]: a };
  }, {});
  console.log(obj);
}
document.querySelector('#theform').addEventListener('submit', nosubmit, {capture: true});
<h1>Multilevel Form</h1>
<form action="#" method="POST" enctype="multipart/form-data" id="theform">
  <input type="hidden" name="_id" value="93242" />
  <input type="hidden" name="_fid" value="45c0ec96929bc0d39a904ab5c7af70ef" />
  <label>Select:
    <select name="uselect">
      <option value="A">A</option>
      <option value="B">B</option>
      <option value="C">C</option>
    </select>
  </label>
  <br /><br />
  <label>Checkboxes one level:<br/>
    <input name="c1[]" type="checkbox" checked value="1"/>v1 
    <input name="c1[]" type="checkbox" checked value="2"/>v2
    <input name="c1[]" type="checkbox" checked value="3"/>v3
  </label>
  <br /><br />
  <label>Checkboxes two levels:<br/>
    <input name="c2[0][]" type="checkbox" checked value="4"/>0 v4 
    <input name="c2[0][]" type="checkbox" checked value="5"/>0 v5
    <input name="c2[0][]" type="checkbox" checked value="6"/>0 v6
    <br/>
    <input name="c2[1][]" type="checkbox" checked value="7"/>1 v7 
    <input name="c2[1][]" type="checkbox" checked value="8"/>1 v8
    <input name="c2[1][]" type="checkbox" checked value="9"/>1 v9
  </label>
  <br /><br />
  <label>Radios:
    <input type="radio" name="uradio" value="yes">YES
    <input type="radio" name="uradio" checked value="no">NO
  </label>
  <br /><br />
  <input type="submit" value="Submit" />
</form>

CarlosH.
sumber
2
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});versi jagoan es2018
nackjicholson
1
@nackjicholson Ya, Anda benar, menghilangkan .entries () dan elemen [k, v] menyederhanakan kode. Saya akan menulis ulang kode untuk memasukkan perbaikan ini. Namun milik Anda masih akan menimpa nilai yang berulang.
CarlosH.
3
Sementara saya menghargai usaha - kode seperti ini tidak masuk akal. Tidak ada yang ingin melihat huruf untuk variabel dan objek, ini bukan 1985.
Tom Stickel
4

Metode FormData .entriesdan for ofekspresi tidak didukung di IE11 dan Safari.

Ini adalah versi yang lebih sederhana untuk mendukung Safari, Chrome, Firefox dan Edge

function formDataToJSON(formElement) {    
    var formData = new FormData(formElement),
        convertedJSON = {};

    formData.forEach(function(value, key) { 
        convertedJSON[key] = value;
    });

    return convertedJSON;
}

Peringatan: jawaban ini tidak berfungsi di IE11.
FormData tidak memiliki forEachmetode di IE11.
Saya masih mencari solusi akhir untuk mendukung semua browser utama.

Tomas Prado
sumber
ini sempurna! kami harus mendukung browser lama dan penggunaan iterator tidak terlalu intuitif.
Peter Hawkins
4

Jika Anda memerlukan dukungan untuk membuat serialisasi bidang bersarang, mirip dengan cara PHP menangani bidang formulir, Anda dapat menggunakan fungsi berikut

function update(data, keys, value) {
  if (keys.length === 0) {
    // Leaf node
    return value;
  }

  let key = keys.shift();
  if (!key) {
    data = data || [];
    if (Array.isArray(data)) {
      key = data.length;
    }
  }

  // Try converting key to a numeric value
  let index = +key;
  if (!isNaN(index)) {
    // We have a numeric index, make data a numeric array
    // This will not work if this is a associative array 
    // with numeric keys
    data = data || [];
    key = index;
  }
  
  // If none of the above matched, we have an associative array
  data = data || {};

  let val = update(data[key], keys, value);
  data[key] = val;

  return data;
}

function serializeForm(form) {
  return Array.from((new FormData(form)).entries())
    .reduce((data, [field, value]) => {
      let [_, prefix, keys] = field.match(/^([^\[]+)((?:\[[^\]]*\])*)/);

      if (keys) {
        keys = Array.from(keys.matchAll(/\[([^\]]*)\]/g), m => m[1]);
        value = update(data[prefix], keys, value);
      }
      data[prefix] = value;
      return data;
    }, {});
}

document.getElementById('output').textContent = JSON.stringify(serializeForm(document.getElementById('form')), null, 2);
<form id="form">
  <input name="field1" value="Field 1">
  <input name="field2[]" value="Field 21">
  <input name="field2[]" value="Field 22">
  <input name="field3[a]" value="Field 3a">
  <input name="field3[b]" value="Field 3b">
  <input name="field3[c]" value="Field 3c">
  <input name="field4[x][a]" value="Field xa">
  <input name="field4[x][b]" value="Field xb">
  <input name="field4[x][c]" value="Field xc">
  <input name="field4[y][a]" value="Field ya">
  <input name="field5[z][0]" value="Field z0">
  <input name="field5[z][]" value="Field z1">
  <input name="field6.z" value="Field 6Z0">
  <input name="field6.z" value="Field 6Z1">
</form>

<h2>Output</h2>
<pre id="output">
</pre>

Joyce Babu
sumber
1
Perlu memperbarui nilai default "data" dari larik "[]" ke objek "{}" dalam "pembaruan fungsi (data, kunci, nilai) {" ini menghapus masalah larik kosong.
Chintan Mathukiya
Saya juga menyarankan untuk menambahkan filter array sebelum mengurangi untuk menghapus bidang kosong dari objek akhir
Ednilson Maia
@ChintanMathukiya Maia Dapatkah Anda berbagi masukan sampel yang keluarannya tidak diharapkan?
Joyce Babu
@ Ednilson Dapatkah Anda berbagi data sampel yang Anda lihat keluaran lariknya kosong?
Joyce Babu
3

Jika Anda menggunakan lodash, itu bisa dilakukan dengan singkat fromPairs

import {fromPairs} from 'lodash';

const object = fromPairs(Array.from(formData.entries()));
Erik van Velzen
sumber
2

Anda bisa mencobanya

formDataToJSON($('#form_example'));

# Create a function to convert the serialize and convert the form data
# to JSON
# @param : $('#form_example');
# @return a JSON Stringify
function formDataToJSON(form) {
    let obj = {};
    let formData = form.serialize();
    let formArray = formData.split("&");

    for (inputData of formArray){
        let dataTmp = inputData.split('=');
        obj[dataTmp[0]] = dataTmp[1];
    }
    return JSON.stringify(obj);
}
Ivan Fretes
sumber
2

Meskipun jawaban dari @dzuc sudah sangat bagus, Anda dapat menggunakan array destructuring (tersedia di browser modern atau dengan Babel) untuk membuatnya lebih elegan:

// original version from @dzuc
const data = Array.from(formData.entries())
  .reduce((memo, pair) => ({
    ...memo,
    [pair[0]: pair[1],
  }), {})

// with array destructuring
const data = Array.from(formData.entries())
  .reduce((memo,[key, value]) => ({
    ...memo,
    [key]: value,
  }), {})
Jeremias Erbs
sumber
2

Satu kalimat yang melecehkan!

Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});

Hari ini saya belajar firefox memiliki dukungan penyebaran objek dan penghancuran array!

nackjicholson
sumber
1

Jika item berikut memenuhi kebutuhan Anda, Anda beruntung:

  1. Anda ingin mengubah array array seperti [['key','value1'], ['key2','value2'](seperti yang diberikan FormData) menjadi key-> value object {key1: 'value1', key2: 'value2'}dan mengubahnya menjadi string JSON.
  2. Anda menargetkan browser / perangkat dengan interpreter ES6 terbaru atau sedang menyusun sesuatu seperti babel.
  3. Anda menginginkan cara terkecil untuk mencapai ini.

Berikut kode yang Anda perlukan:

const data = new FormData(document.querySelector('form'));
const json = JSON.stringify(Array.from(data).reduce((o,[k,v])=>(o[k]=v,o),{}));

Semoga ini bisa membantu seseorang.

KyleFarris
sumber
1

Saya tidak melihat penyebutan metode FormData.getAll sejauh ini.

Selain mengembalikan semua nilai yang terkait dengan kunci yang diberikan dari dalam objek FormData, itu menjadi sangat sederhana menggunakan metode Object.fromEntries seperti yang ditentukan oleh orang lain di sini.

var formData = new FormData(document.forms[0])

var obj = Object.fromEntries(
  Array.from(formData.keys()).map(key => [
    key, formData.getAll(key).length > 1 ? 
      formData.getAll(key) : formData.get(key)
  ])
)

Cuplikan beraksi

var formData = new FormData(document.forms[0])

var obj = Object.fromEntries(Array.from(formData.keys()).map(key => [key, formData.getAll(key).length > 1 ? formData.getAll(key) : formData.get(key)]))

document.write(`<pre>${JSON.stringify(obj)}</pre>`)
<form action="#">
  <input name="name" value="Robinson" />
  <input name="items" value="Vin" />
  <input name="items" value="Fromage" />
  <select name="animals" multiple id="animals">
    <option value="tiger" selected>Tigre</option>
    <option value="turtle" selected>Tortue</option>
    <option value="monkey">Singe</option>
  </select>
</form>

OpSocket
sumber
0

Bekerja untuk saya

                var myForm = document.getElementById("form");
                var formData = new FormData(myForm),
                obj = {};
                for (var entry of formData.entries()){
                    obj[entry[0]] = entry[1];
                }
                console.log(obj);
Shahid Hussain Abbasi
sumber
Ini tidak akan menangani beberapa nilai yang dipilih dari <select multiple>atau<input type="checkbox">
beberapa
0

Dalam bentuk kasus saya Data adalah data, basis api mengharapkan objek tetapi data berisi objek serta semua barang lainnya jadi saya mencoba data.value it works !!!

Rahul solanki
sumber
0

Saya datang terlambat di sini. Namun, saya membuat metode sederhana yang memeriksa input type = "checkbox"

var formData = new FormData($form.get(0));
        var objectData = {};
        formData.forEach(function (value, key) {
            var updatedValue = value;
            if ($('input[name="' + key + '"]').attr("type") === "checkbox" && $('input[name="' + key + '"]').is(":checked")) {
                updatedValue = true; // we don't set false due to it is by default on HTML
            }
            objectData[key] = updatedValue;
        });
var jsonData = JSON.stringify(objectData);

Saya harap ini membantu orang lain.

acido
sumber
-1

Anda dapat melakukan pekerjaan ini dengan mudah tanpa menggunakan sesuatu yang istimewa. Kode seperti di bawah ini sudah cukup.

var form = $(e.currentTarget);

var formData = objectifyForm(form);


function objectifyForm(formArray) {

    var returnArray = {};
    for (var i = 0; i < formArray[0].length; i++) {
        var name = formArray[0][i]['name'];
        if (name == "") continue;
        if (formArray[0][i]['type'] == "hidden" && returnArray[name] != undefined) continue;
        if ($(formArray[0][i]).attr("type") == "radio") {
            var radioInputs = $("[name='" + name + "']");
            var value = null;
            radioInputs.each(function (radio) {
                if ($(this)[0].checked == true) {
                    value = $(this).attr("id").split("_")[$(this).attr("id").split("_").length - 1];
                }
            });
            returnArray[name] = value;
        }
        else if ($(formArray[0][i]).attr("type") == "checkbox") {
            returnArray[name] = $(formArray[0][i])[0].checked;
        }
        else
            returnArray[name] = formArray[0][i]['value'];
    }



    return returnArray;
};
nercan
sumber