Как конвертировать FormData (объект HTML5) в JSON

Как преобразовать объект HTML5 FormData в JSON? Без Jquery и обработки вложенных свойств в FormData как объект.

Ответ 1

Вы также можете использовать forEach непосредственно для объекта FormData:

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

UPDATE:

И для тех, кто предпочитает то же решение с стрелками ES6:

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

ОБНОВЛЕНИЕ 2:

А для тех, кому нужна поддержка списков с множественным выбором или других элементов формы с несколькими значениями (поскольку под ответом по этой проблеме так много комментариев, я добавлю возможное решение):

var object = {};
formData.forEach((value, key) => {
    if(!object.hasOwnProperty(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 является отправка их через HTTP-запрос XML на сервер, вы можете отправить объект FormData напрямую, не преобразовывая его. Так просто, как это:

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

См. также also Использование объектов FormData в MDN для справки:

ОБНОВЛЕНИЕ 4:

Как упоминалось в одном из комментариев ниже моего ответа, метод JSON stringify не будет работать "из коробки" для всех типов объектов. Для получения дополнительной информации о том, какие типы поддерживаются, я хотел бы обратиться к разделу описания в документации по MDN JSON.stringify.

В описании также упоминается, что:

Если значение имеет метод toJSON(), оно определяет, какие данные будут сериализованы.

Это означает, что вы можете предоставить свой собственный метод сериализации toJSON с логикой для сериализации ваших пользовательских объектов. Таким образом, вы можете быстро и легко создать поддержку сериализации для более сложных деревьев объектов.

Ответ 2

В 2019 году такая задача стала сверхлегкой.

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

Object.fromEntries: поддерживается в Chrome 73+, Firefox 63+, Safari 12.1

Ответ 3

Вот способ сделать это в более функциональном стиле, без использования библиотеки.

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>

Ответ 4

Если у вас несколько записей с тем же именем, например, если вы используете <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 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 или entries в 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 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 );
  }

Ответ 5

Вы можете достичь этого с помощью объекта 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);

});

Ответ 6

Простая в использовании функция

Я создал Функция для этого

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

В этом коде я создал пустую переменную JSON, используя цикл for Я использовал key из объекта formData Object для JSON Keys в каждом Itration.

Вы найдете этот код в моей библиотеке JS на GitHub. Предложите мне, если он нуждается в улучшении. Я разместил здесь код https://github.com/alijamal14/Utilities/blob/master/Utilities.js p >

Ответ 7

Этому посту уже год... но мне действительно очень нравится ответ ES6 @dzuc. Однако он неполон, поскольку не может обрабатывать несколько вариантов выбора или флажков. Это уже указывалось, и кодовые решения были предложены. Я нахожу их тяжелыми и не оптимизированными. Поэтому я написал 2 версии на основе @dzuc для обработки этих случаев:

  • Для форм в стиле 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);

Однострочная версия 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);

Однострочная версия 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, поддерживающей многоуровневые массивы.

Так как в прошлый раз я писал предыдущий второй случай, на работе случился случай, когда форма 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>

Ответ 8

Метод FormData .entries и выражение for 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 не имеет метода forEach в IE11.
Я все еще ищу окончательное решение для поддержки всех основных браузеров.

Ответ 9

Если вы используете lodash, это можно сделать лаконично с помощью fromPairs

import {fromPairs} from 'lodash';

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

Ответ 10

Несмотря на то, что ответ от @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,
  }), {})

Ответ 11

Вы можете попробовать это

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

Ответ 12

Если следующие предметы соответствуют вашим потребностям, вам повезло:

  1. Вы хотите преобразовать массив массивов, таких как [['key','value1'], ['key2','value2'] (например, что дает вам FormData) в объект значения key->, например {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),{}));

Надеюсь, это кому-нибудь поможет.

Ответ 13

Оскорбительный лайнер!

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

Сегодня я узнал, что у Firefox есть поддержка распространения объектов и деструктуризация массива!

Ответ 14

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>

Ответ 15

Работал для меня

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