FormData(HTML5 Object)をJSONに変換する方法


104

HTML5 FormDataオブジェクトをJSONに変換する方法は?Jqueryを使用せず、FormDataのネストされたプロパティをオブジェクトのように処理します。


2
あなたは何をしようとしているのですか?DOESがJSON.stringify()できますか?多分あなたは他の方法で行われるかもしれない何かを修正しようとしていますか?
Justinas 2017年


3
javascriptオブジェクトをjsonに変換したくない、またはJquery.serialize()を使用したくないので、重複していません
Leonardo Villela

これを確認してください:stackoverflow.com/a/39248551/6293856
Bhavik Hirani

回答:


145

また、使用することができますforEachFormData直接オブジェクト:

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

更新:

ES6の矢印関数を使用した同じソリューションを好む人のために:

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

更新2:

そして、複数選択リストまたは複数の値を持つ他のフォーム要素のサポートを必要とする人のために(この問題に関する回答の下に非常に多くのコメントがあるため、私は可能な解決策を追加します)

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

ここでは、単純な複数選択リストでこのメソッドを使用することを示すフィドルがあります。

更新3:

ここで終わることに注意してください。フォームデータをjsonに変換する目的がXML HTTPリクエストを介してサーバーに送信することであるFormData場合、オブジェクトを変換せずに直接送信できます。これと同じくらい簡単です:

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

MDNでのFormDataオブジェクトの使用参照してください。

更新4:

以下のコメントの1つで述べたように、JSON stringifyメソッドは、すべてのタイプのオブジェクトに対してそのままでは機能しません。サポートされているタイプの詳細については、以下のMDNドキュメントの「説明」セクションを参照してください。JSON.stringify

説明では、次の点にも言及しています。

値にtoJSON()メソッドがある場合、シリアル化するデータを定義する必要があります。

つまりtoJSON、カスタムオブジェクトをシリアル化するロジックを備えた独自のシリアル化メソッドを提供できます。このように、より複雑なオブジェクトツリーのシリアル化サポートをすばやく簡単に構築できます。


1
@TomasPradoからの回答で述べたように、IE11のサポートが必要ないことを確認してください。
Wilt

4
これは複数選択フォーム要素では機能しません。同じキーを共有するため、最後に選択された要素のみを返す値を上書きしてしまうからです
Sean

1
@Sean方には複数の値と連動するように答えを与えた<SELECT MULTIPLE><INPUT type="checkbox">同じ名前を持つ、配列に値を変換することによって。
いくつかの

formDataはセリエではありません。どのように反復できますか?回答は受け付けましたが、見落としました。
Nuri YILMAZ

4
複数選択などの必要性がない限り、答えJSON.stringify(Object.fromEntries(formData));はこれよりずっと良い
Tom Stickel

108

2019年、この種のタスクは非常に簡単になりました。

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

Object.fromEntries:Chrome 73以降、Firefox 63以降、Safari 12.1でサポート


2
これを投稿するためにここに来て、このスレッドを見て、何年にもわたって回答がどのように進化したかを見てみ
Marcin

13
これは、同じ名前のフィールドが複数あるフォームでは正しく機能しないようです。
JukkaP

3
それは2020であり、これは複数の選択された値<select multiple>または<input type="checkbox"> 😞を処理しません
一部の

4
formData.entriesを使用する方が良い:JSON.stringify(Object.fromEntries(formData.entries()));
Kohver

22

これは、ライブラリを使用せずに、より機能的なスタイルで実行する方法です。

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

例:

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
ここでベストアンサー。ありがとう:)
チャンキーチャンク

4
私はこの答えが本当に好きですが、それでも複数のアイテムを処理しません。これらのケースを処理するために、これに基づいて新しい回答を投稿しました。
CarlosH。

9

同じ名前のエントリが複数ある場合、たとえば複数のエントリを使用し<SELECT multiple>ている場合<INPUT type="checkbox">、そのことに注意して値の配列を作成する必要があります。それ以外の場合は、最後に選択した値のみを取得します。

これが最新のES6バリアントです。

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

(それはサポートしていないため、まだ、IE11でサポートされていないが、少し古いコードForEachまたはentriesFormData

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()を使用して実現できます。オブジェクトます。このFormDataオブジェクトには、キーの各要素のnameプロパティと、送信された値の値を使用して、フォームの現在のキー/値が入力されます。また、ファイル入力コンテンツをエンコードします。

例:

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

});

これはjsonを生成しません
Liam

1
@Liamフォーム要素でこれを試しましたか?そして、なぜそれがJSONオブジェクトを生成しないのか教えてください?
GiriB 2017年

1
jsonオブジェクトのようなものはありません。Jsonは文字列表記
Liam

1
@Liamオブジェクトの作成後、JSON.stringify(result)を使用できます。そして、私は私の答えを編集しました。これをチェックしてください。そして、反対票を撤回します。
GiriB 2017年

1
あなたはES6を使用している場合にも、ステートメントのためのより表現することができます: for (const [key, value] of formData.entries())
テディZetterlund

7

使いやすい機能

このための関数を作成しまし

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

    return ConvertedJSON
}

使用例

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

このコードでは、forループを使用して空のJSON変数を作成しkeyました。すべてのItrationでformDataオブジェクトからJSONキーへのs を使用しました。

GitHubのJSライブラリでこのコードを見つけたら、改善が必要な場合は、ここにコードを配置してください。https://github.com/alijamal14/Utilities/blob/master/Utilities.js


1
@zulukの説明 ありがとう
Ali Jamal

これは、<select multiple>またはの選択された複数の値を処理しません<input type="checkbox">
いくつかの

5

この投稿は1年前のものですが、ES6の@dzucの回答が本当に好きです。ただし、複数の選択またはチェックボックスを処理できないため、不完全です。これはすでに指摘されており、コードソリューションが提供されています。重くて最適化されていないことがわかりました。したがって、これらのケースを処理するために、@ dzucに基づいて2つのバージョンを作成しました。

  • 複数のアイテム名が単純に繰り返されるASPスタイルフォームの場合。
let r=Array.from(fd).reduce(
  (o , [k,v]) => (
     (!o[k])
     ? {...o , [k] : v}
     : {...o , [k] : [...o[k] , v]}
   )
   ,{}
);
let obj=JSON.stringify(r);

1行Hotshotバージョン:

Array.from(fd).reduce((o,[k,v])=>((!o[k])?{...o,[k]:v}:{...o,[k]:[...o[k],v]}),{});
  • 複数のアイテム名に[]サフィックスが必要なPHPスタイルのフォームの場合。
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);

1行Hotshotバージョン:

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}),{});
  • マルチレベル配列をサポートするPHPフォームの拡張。

前回、前の2番目のケースを書いてから、職場でPHPフォームにマルチレベルのチェックボックスがあるというケースがありました。以前のケースとこのケースをサポートするために新しいケースを書きました。このケースをより適切に示すスニペットを作成しました。このデモの結果はコンソールに表示されますが、必要に応じて変更してください。パフォーマンスを損なうことなく、できる限り最適化しようとしましたが、人間の読みやすさが損なわれました。配列がオブジェクトであり、配列を指す変数が参照として保持されることを利用します。このホットショットはありません、私のゲストになります。

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バージョンes2018
nackjicholson

1
@nackjicholsonええ、そうです。.entries()を省略し、[k、v]要素はコードを簡略化します。これらの改善を含むようにコードを書き直します。ただし、あなたの値は繰り返し値で上書きされます。
CarlosH。

3
私は努力に感謝していますが、このようなコードはばかげています。変数やオブジェクトの文字を見たくないので、これは1985
。– Tom Stickel

4

FormDataメソッド.entriesfor of、IE11およびSafari ではサポートされていません

これは、Safari、Chrome、Firefox、およびEdgeをサポートする簡単なバージョンです

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

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

    return convertedJSON;
}

警告:この回答はIE11では機能しません。
FormDataはIE11にメソッドがありませんforEach
すべての主要なブラウザーをサポートするための最終的な解決策をまだ探しています。


これは完璧です!古いブラウザをサポートする必要があり、イテレータの使用はあまり直感的ではありません。
Peter Hawkins

3

あなたがlodashを使用しているなら、それは簡潔に行うことができます fromPairs

import {fromPairs} from 'lodash';

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

3

PHPがフォームフィールドを処理する方法と同様に、ネストされたフィールドのシリアル化のサポートが必要な場合は、次の関数を使用できます。

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
「関数update(data、keys、value){」で配列「[]」からオブジェクト「{}」に「データ」のデフォルト値を更新する必要があるため、空の配列の問題が削除されます。
Chintan Mathukiya

最終的なオブジェクトから空のフィールドを削除するために、reduceの前に配列フィルターを追加することもお勧めします
Ednilson Maia

@ChintanMathukiya Maia予期しない出力が発生しているサンプル入力を共有できますか?
ジョイスバブ

@Ednilson空の配列出力が表示されているサンプルデータを共有できますか?
ジョイスバブ

2

あなたはこれを試すことができます

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からの回答はすでに非常に優れていますが、配列の構造化(最近のブラウザーまたはBabelで利用可能)を使用して、さらにエレガントにすることができます。

// 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

虐待的なワンライナー!

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

今日、Firefoxにオブジェクトスプレッドのサポートと配列のデストラクタリングがあることを学びました!


1

以下のアイテムがあなたのニーズを満たしている場合、あなたは幸運です:

  1. [['key','value1'], ['key2','value2'](FormDataが提供するような)配列の配列をkey-> valueオブジェクトのよう{key1: 'value1', key2: 'value2'}に変換し、それをJSON文字列に変換したいとします。
  2. 最新のES6インタープリターを備えたブラウザー/デバイスをターゲットにしている、またはbabelなどでコンパイルしています。
  3. これを達成するための最も簡単な方法が必要です。

必要なコードは次のとおりです。

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

これが誰かを助けることを願っています。


1

これまでのところ、FormData.getAllメソッドについての言及はありません。

FormDataオブジェクト内から特定のキーに関連付けられたすべての値を返すだけでなく、他のユーザーがここで指定したObject.fromEntriesメソッドを使用すると、非常に簡単になります。

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

実際のスニペット

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

私のために働いた

                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><input type="checkbox">
いくつかの

0

私の場合、データはデータでしたが、ファイアベースはオブジェクトを期待していましたが、データにはオブジェクトと他のすべてのものが含まれているので、data.valueを試しました!!!


0

私はここに遅れて到着します。しかし、私は入力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);

これが他の誰かの役に立つことを願っています。


-1

特別なことをしなくても簡単にできます。以下のようなコードで十分です。

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;
};
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.