FormData'yı (HTML5 Nesnesi) JSON'a dönüştürme


112

HTML5 FormData nesnesini JSON'a nasıl dönüştürebilirim? Jquery olmadan ve FormData'daki yuvalanmış özellikleri bir nesne gibi işleme olmadan.


2
Ne yapmaya çalışıyorsun? Yardımcı JSON.stringify()olur mu? Belki başka bir şekilde yapılabilecek bir şeyi onarmaya çalışırsınız?
Justinas


4
Bir javascript nesnesini json'a dönüştürmek istemediğim için yinelenmiyor ve Jquery.serialize ()
Leonardo Villela

Yanıtlar:


158

Doğrudan nesne forEachüzerinde de kullanabilirsiniz FormData:

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

GÜNCELLEME:

Ve ES6 ok fonksiyonlarıyla aynı çözümü tercih edenler için :

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

GÜNCELLEME 2:

Ve çoklu seçim listeleri veya birden fazla değere sahip diğer form öğeleri için destek isteyenler için (bu konuyla ilgili cevabın altında çok fazla yorum olduğundan, olası bir çözüm ekleyeceğim) :

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

Burada basit bir çoklu seçim listesi ile bu yöntemin kullanımını gösteren bir Fiddle .

GÜNCELLEME 3:

Burada bitenler için bir yan not olarak, form verilerini json'a dönüştürmenin amacı, onu bir XML HTTP isteği aracılığıyla bir sunucuya göndermekse, FormDatanesneyi dönüştürmeden doğrudan gönderebilirsiniz . Bu kadar basit:

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

Başvuru için MDN'de FormData Nesnelerini Kullanma konusuna da bakın :

GÜNCELLEME 4:

Cevabımın altındaki yorumlardan birinde belirtildiği gibi, JSON stringifyyöntemi her tür nesne için kutudan çıkmaz. Hangi türlerin desteklendiği hakkında daha fazla bilgi için MDN belgelerinin Açıklama bölümüneJSON.stringify başvurmak istiyorum .

Açıklamada ayrıca şu hususlardan bahsedilmektedir:

Değerin toJSON () yöntemi varsa, hangi verilerin serileştirileceğini tanımlamak sorumludur.

Bu toJSON, özel nesnelerinizi serileştirme mantığıyla kendi serileştirme yönteminizi sağlayabileceğiniz anlamına gelir . Bunun gibi, daha karmaşık nesne ağaçları için hızlı ve kolay bir şekilde serileştirme desteği oluşturabilirsiniz.


1
@TomasPrado'nun yanıtında belirtildiği gibi, IE11 için desteğe ihtiyacınız olmadığından emin olun.
Wilt

4
Bu, yalnızca son seçilen öğeyi döndüren değerlerin üzerine yazmanızla aynı anahtarı paylaştıkları için çoklu seçim form öğeleriyle çalışmaz
Sean

1
@Sean ben birden çok değerle eserler olduğunu bir cevap verdi <SELECT MULTIPLE>ve <INPUT type="checkbox">aynı adla bir diziye değerini dönüştürerek.
bazı

formData bir seri değil. nasıl yineleyebilirsin? cevap kabul edildi, ancak bir şey gözden kaçtı.
Nuri YILMAZ

4
Çoklu seçim vb. Gerekmedikçe cevap JSON.stringify(Object.fromEntries(formData));çok daha güzel
Tom Stickel

112

2019'da bu tür görevler çok kolay hale geldi.

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

Object.fromEntries: Chrome 73+, Firefox 63+, Safari 12.1'de desteklenir


2
Bunu göndermek için buraya geldim, bu konuya bakmayı ve yanıtların yıllar içinde nasıl geliştiğini görmeyi seviyorum
Marcin

14
Bu, aynı ada sahip birden çok alana sahip formlarda düzgün çalışmıyor gibi görünüyor.
JukkaP

3
Yıl 2020 ve bu birden fazla seçilen değeri <select multiple>veya <input type="checkbox">😞'yi işlemez
bazıları

4
FormData.entries'i kullanmak daha iyi:JSON.stringify(Object.fromEntries(formData.entries()));
Kohver

22

İşte bunu bir kütüphane kullanmadan daha işlevsel bir tarzda yapmanın bir yolu.

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

Misal:

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>


1
En iyi cevap burada. Teşekkürler :)
Chunky Chunk

4
Bu cevabı gerçekten beğendim ama yine de birden fazla maddeyi ele almıyorum. Bu vakaları ele almak için buna dayalı yeni bir cevap gönderdim.
CarlosH.

10

Aynı ada sahip birden fazla giriş varsa, kullanırsanız örneğin <SELECT multiple>veya birden sahip <INPUT type="checkbox">aynı isimde, bu özen ve değerin bir dizi yapmak gerekir. Aksi takdirde yalnızca son seçilen değeri alırsınız.

İşte modern ES6 varyantı:

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

Biraz daha eski kod (ancak desteklemediği ForEachveya entriesaçık olmadığı için hala IE11 tarafından desteklenmiyor 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 );
  }

7

FormData () nesnesini kullanarak bunu başarabilirsiniz . Bu FormData nesnesi, anahtarlar için her öğenin name özelliği ve değerler için gönderilen değerleri kullanılarak formun geçerli anahtarları / değerleri ile doldurulur. Ayrıca dosya giriş içeriğini de kodlayacaktır.

Misal:

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

});

Bu json üretmez
Liam

1
@Liam Bunu form öğeleriyle denediniz mi? Ve neden JSON nesnesi üretmediğini bana bildirin.
GiriB

1
Json nesnesi diye bir şey yoktur. Json bir dizge gösterimidir
Liam

1
@Liam Nesne oluşturulduktan sonra JSON.stringify (sonuç) kullanabilir. Ve cevabımı düzenledim. Lütfen kontrol et. Ve olumsuz oyu geri çekin.
GiriB

1
ES6 kullanıyorsanız, for of ifadesini daha anlamlı hale de getirebilirsiniz:for (const [key, value] of formData.entries())
Teddy Zetterlund

7

Kullanımı Kolay İşlev

Bunun İçin Bir Fonksiyon Oluşturdum

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

    return ConvertedJSON
}

Örnek Kullanım

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

Bu kodda fordöngüyü kullanarak boş JSON değişkeni oluşturdum key. Her Itration'da formData Object'ten JSON Keys'e kadar s kullandım .

Bu Kodu GitHub'daki JS Kitaplığımda Buluyorsunuz İyileştirme Gerekirse Bana Önerin Kodu Buraya Yerleştirdim https://github.com/alijamal14/Utilities/blob/master/Utilities.js


1
@zuluk Açıklaması Teşekkür
Ali Jamal

Bu, <select multiple>veya birden çok seçilen değeri işlemez <input type="checkbox">.
bazı

5

Bu gönderi zaten bir yaşında ... ama ES6 @dzuc cevabını gerçekten çok seviyorum. Ancak, birden çok seçim veya onay kutusu işlenemediği için eksiktir. Bu zaten işaret etti ve kod çözümleri sunuldu. Onları ağır buluyorum ve optimize edilmemiş buluyorum. Bu nedenle, bu durumları ele almak için @ dzuc'a dayalı 2 sürüm yazdım:

  • Birden çok öğe adının basitçe tekrarlanabildiği ASP stili formlar için.
let r=Array.from(fd).reduce(
  (o , [k,v]) => (
     (!o[k])
     ? {...o , [k] : v}
     : {...o , [k] : [...o[k] , v]}
   )
   ,{}
);
let obj=JSON.stringify(r);

Tek satırlık Hotshot sürümü:

Array.from(fd).reduce((o,[k,v])=>((!o[k])?{...o,[k]:v}:{...o,[k]:[...o[k],v]}),{});
  • Birden çok öğe adının bir []son eki olması gereken PHP stili formlar için .
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);

Tek satırlık Hotshot sürümü:

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}),{});
  • Çok seviyeli dizileri destekleyen PHP formunun uzantısı.

Geçen sefer önceki ikinci vakayı yazdığımdan beri, işte PHP formunun çoklu seviyelerde onay kutularına sahip olduğu bir durum geldi. Önceki vakayı ve bunu desteklemek için yeni bir vaka yazdım. Bu davayı daha iyi sergilemek için bir pasaj oluşturdum, sonuç bu demo için konsolda gösterilir, bunu ihtiyacınıza göre değiştirin. Performanstan ödün vermeden yapabildiğim en iyi şekilde optimize etmeye çalıştım, ancak bazı insan okunabilirliğini tehlikeye attı. Dizilerin nesneler olması ve dizilere işaret eden değişkenlerin referans olarak tutulması avantajını kullanır. Bunun için önemli bir şey yok, konuğum ol.

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>


2
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});hotshot version es2018
nackjicholson

1
@nackjicholson Yeap, haklısın, .entries () 'i atlamak ve [k, v] öğesi kodu basitleştirir. Bu iyileştirmeleri içerecek şekilde kodu yeniden yazacağım. Ancak sizinki yine de tekrarlanan değerlerin üzerine yazacaktır.
CarlosH.

3
Çabayı takdir etsem de - bunun gibi bir kod saçmadır. Kimse değişkenler ve nesneler için harflere bakmak istemez, bu 1985 değil.
Tom Stickel

4

FormData yöntemi .entriesve for ofifade , IE11 ve Safari'de desteklenmez .

Safari, Chrome, Firefox ve Edge'i desteklemek için daha basit bir sürüm burada

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

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

    return convertedJSON;
}

Uyarı: bu cevap IE11'de çalışmıyor.
FormData'nın IE11'de bir forEachyöntemi yoktur.
Hala tüm büyük tarayıcıları desteklemek için nihai bir çözüm arıyorum.


bu harika! eski tarayıcıları desteklemeliyiz ve yineleyici kullanımı pek sezgisel değildir.
Peter Hawkins

4

PHP'nin form alanlarını işleme biçimine benzer şekilde, iç içe geçmiş alanları serileştirmek için desteğe ihtiyacınız varsa, aşağıdaki işlevi kullanabilirsiniz

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>


1
"Veri" varsayılan değerini "[]" dizisinden "işlev güncellemesinde" {} "nesnesine güncellemeniz gerekir (veriler, anahtarlar, değer) {" boş dizi sorununu ortadan kaldırır.
Chintan Mathukiya

Son nesneden boş alanları kaldırmak için azaltmadan önce bir dizi filtresi eklemenizi de öneririm
Ednilson Maia

@ChintanMathukiya Maia Beklenmedik çıktı elde ettiğiniz örnek girdiyi paylaşabilir misiniz?
Joyce Babu

@Ednilson Boş dizi çıktısı gördüğünüz örnek verileri paylaşabilir misiniz?
Joyce Babu

3

Lodash kullanıyorsanız, bunu kısaca yapabilirsiniz. fromPairs

import {fromPairs} from 'lodash';

const object = fromPairs(Array.from(formData.entries()));

2

Bunu deneyebilirsin

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

2

@Dzuc'un cevabı zaten çok iyi olsa da, onu biraz daha zarif hale getirmek için dizi yok etmeyi (modern tarayıcılarda veya Babel'de mevcut) kullanabilirsiniz:

// 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,
  }), {})

2

Kötü niyetli tek satırlık!

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

Bugün firefox'un nesne yayma desteği ve dizi yıkımı olduğunu öğrendim!


1

Aşağıdaki öğeler ihtiyaçlarınızı karşılıyorsa, şanslısınız:

  1. Bir dizi diziyi [['key','value1'], ['key2','value2'](FormData'nın size verdiği gibi) benzeri bir anahtar-> değer nesnesine {key1: 'value1', key2: 'value2'}dönüştürmek ve onu bir JSON dizesine dönüştürmek istiyorsunuz.
  2. En son ES6 yorumlayıcısına sahip tarayıcıları / cihazları hedefliyorsunuz veya babel gibi bir şeyle derliyorsunuz.
  3. Bunu başarmanın en küçük yolunu istiyorsunuz.

İşte ihtiyacınız olacak kod:

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

Umarım bu birine yardımcı olur.


1

Şimdiye kadar FormData.getAll yönteminden hiç bahsetmedim .

FormData nesnesinin içinden belirli bir anahtarla ilişkili tüm değerleri döndürmenin yanı sıra, burada başkaları tarafından belirtildiği gibi Object.fromEntries yöntemini kullanarak gerçekten basitleşir .

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

Snippet iş başında

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>


0

Benim için çalıştı

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

<select multiple>Veya birden fazla seçilen değeri işlemez<input type="checkbox">
bazı

0

Benim durumumda Veri veri idi, yangın üssü bir nesne bekliyordu ancak veriler nesnenin yanı sıra diğer tüm şeyleri içeriyor, bu yüzden veriyi denedim. İşe yaradı !!!


0

Buraya geç geliyorum. Ancak, input type = "checkbox" ı kontrol eden basit bir yöntem yaptım

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

Umarım bu başkasına yardımcı olur.


-1

Bu işi özel bir şey kullanmadan rahatlıkla yapabilirsiniz. Aşağıdaki gibi bir kod yeterli olacaktır.

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;
};
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.