Як перетворити об’єкт HTML5 FormData на JSON? Без Jquery та обробки вкладених властивостей у FormData як об’єкта.
Як перетворити об’єкт HTML5 FormData на JSON? Без Jquery та обробки вкладених властивостей у FormData як об’єкта.
Відповіді:
Ви також можете використовувати безпосередньо forEach
на FormData
об'єкті:
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);
А для тих, хто хоче підтримку списків із декількома виборами чи інших елементів форми з кількома значеннями (оскільки під відповідь щодо цього питання є стільки коментарів, я додаю можливе рішення) :
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);
Ось скрипка, що демонструє використання цього методу за допомогою простого списку з декількома виборами.
Як допоміжне зауваження для тих, хто опинився тут, у тому випадку, якщо метою перетворення даних форми у json є відправка їх через XML-запит HTTP на сервер, ви можете надіслати FormData
об’єкт безпосередньо, не перетворюючи його. Так просто, як це:
var request = new XMLHttpRequest();
request.open("POST", "http://example.com/submitform.php");
request.send(formData);
Див. Також Використання об’єктів FormData на MDN для довідки :
Як згадувалося в одному з коментарів нижче моєї відповіді, stringify
метод JSON не спрацює не для всіх типів об'єктів. Для отримання додаткової інформації про те, які типи підтримуються, я хотів би звернутися до розділу "Опис" в документації MDNJSON.stringify
.
В описі також згадується, що:
Якщо значення має метод toJSON (), він відповідає за те, які дані будуть серіалізовані.
Це означає, що ви можете забезпечити власний toJSON
метод серіалізації логікою для серіалізації своїх користувацьких об'єктів. Подібно до цього ви можете швидко та легко створити підтримку серіалізації для більш складних дерев об’єктів.
<SELECT MULTIPLE>
і <INPUT type="checkbox">
з таким же ім'ям, шляхом перетворення значення в масив.
JSON.stringify(Object.fromEntries(formData));
набагато приємніша
У 2019 році таке завдання стало надзвичайно простим.
JSON.stringify(Object.fromEntries(formData));
Object.fromEntries
: Підтримується в Chrome 73+, Firefox 63+, Safari 12.1
<select multiple>
або <input type="checkbox">
😞
JSON.stringify(Object.fromEntries(formData.entries()));
Ось спосіб зробити це у більш функціональному стилі, без використання бібліотеки.
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>
Якщо у вас є кілька записів з однаковим іменем, наприклад, якщо ви використовуєте <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
або 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'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 );
}
Ви можете досягти цього за допомогою об’єкта 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);
});
for (const [key, value] of formData.entries())
Проста у використанні функція
Я створив для цього функцію
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
s від formData Object до ключів JSON у кожній Itration.
Ви знайдете цей код у моїй бібліотеці JS на GitHub. Запропонуйте мені, якщо це потребує вдосконалення. Я розмістив код тут https://github.com/alijamal14/Utilities/blob/master/Utilities.js
<select multiple>
або <input type="checkbox">
.
Цій публікації вже рік ... але, мені дуже, дуже подобається відповідь ES6 @dzuc. Однак він є неповним, оскільки не вдалося обробити декілька виділень або прапорців. Це вже вказано, і пропонуються кодові рішення. Я вважаю їх важкими та не оптимізованими. Тому я написав 2 версії на основі @dzuc для розгляду цих випадків:
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]}),{});
[]
суфікс.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 має прапорці на багаторівневих рівнях. Я написав нову справу на підтримку попередньої та цієї справи. Я створив фрагмент, щоб краще продемонструвати цей випадок, показ результатів на консолі для цієї демонстрації, змініть це відповідно до ваших потреб. Намагався оптимізувати його якнайкраще, не втрачаючи продуктивності, проте це загрожує деякій людській читабельності. Це перевага, що масиви є об’єктами, а змінні, що вказують на масиви, зберігаються як посилання. Немає гарячих знімків для цього, будьте моїм гостем.
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>
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});
hotshot версія es2018
Метод 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.
Я все ще шукаю остаточне рішення для підтримки всіх основних браузерів.
Якщо ви використовуєте лодаш, це можна зробити коротко fromPairs
import {fromPairs} from 'lodash';
const object = fromPairs(Array.from(formData.entries()));
Якщо вам потрібна підтримка для серіалізації вкладених полів, подібно до того, як 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>
Ви можете спробувати це
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);
}
Незважаючи на те, що відповідь від @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,
}), {})
Зловмисний однокласник!
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});
Сьогодні я дізнався, що firefox має підтримку розповсюдження об’єктів та деструктурування масивів!
Якщо наступні предмети відповідають вашим потребам, вам пощастило:
[['key','value1'], ['key2','value2']
(наприклад, те, що дає вам FormData) у об’єкт key-> value like {key1: 'value1', key2: 'value2'}
і перетворити його у рядок JSON.Ось код, який вам знадобиться:
const data = new FormData(document.querySelector('form'));
const json = JSON.stringify(Array.from(data).reduce((o,[k,v])=>(o[k]=v,o),{}));
Сподіваюся, це комусь допомагає.
Дотепер я не бачив згадок про метод 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>
Працював у мене
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">
У моєму випадку Дані були даними, fire base очікував об'єкт, але дані містять об'єкт, а також всі інші матеріали, тому я спробував data.value це спрацювало !!!
Я прибуваю сюди пізно. Однак я зробив простий метод, який перевіряє тип вводу = "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);
Сподіваюся, це допоможе комусь іншому.
Ви можете легко виконувати цю роботу, не використовуючи нічого особливого. Такого коду, як наведений нижче, буде достатньо.
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;
};
JSON.stringify()
допомагає? Можливо, ви намагаєтесь виправити щось, що може бути зроблено іншим способом?