Jak przekonwertować obiekt FormData HTML5 na JSON? Bez JQuery i obsługi zagnieżdżonych właściwości w FormData jak obiekt.
Jak przekonwertować obiekt FormData HTML5 na JSON? Bez JQuery i obsługi zagnieżdżonych właściwości w FormData jak obiekt.
Odpowiedzi:
Możesz również użyć bezpośrednio forEach
na FormData
obiekcie:
var object = {};
formData.forEach(function(value, key){
object[key] = value;
});
var json = JSON.stringify(object);
A dla tych, którzy wolą to samo rozwiązanie z funkcjami strzałek ES6 :
var object = {};
formData.forEach((value, key) => object[key] = value);
var json = JSON.stringify(object);
A dla tych, którzy chcą obsługiwać listy wielokrotnego wyboru lub inne elementy formularza z wieloma wartościami (ponieważ pod odpowiedzią na ten temat jest tak wiele komentarzy, dodam możliwe rozwiązanie) :
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);
Tutaj Fiddle demonstruje użycie tej metody z prostą listą wielokrotnego wyboru.
Na marginesie dla tych, którzy kończą w tym miejscu, w przypadku, gdy celem konwersji danych formularza na json jest wysłanie ich przez żądanie XML HTTP do serwera, można wysłać FormData
obiekt bezpośrednio, bez konwersji. Tak proste, jak to:
var request = new XMLHttpRequest();
request.open("POST", "http://example.com/submitform.php");
request.send(formData);
Zobacz także Korzystanie z obiektów FormData w MDN :
Jak wspomniano w jednym z komentarzy poniżej, moja odpowiedź, stringify
metoda JSON nie będzie działać po wyjęciu z pudełka dla wszystkich typów obiektów. Aby uzyskać więcej informacji na temat obsługiwanych typów, zapoznaj się z sekcją Opis w dokumentacji MDNJSON.stringify
.
W opisie wspomina się również, że:
Jeśli wartość ma metodę toJSON (), jest odpowiedzialna za określenie, jakie dane będą serializowane.
Oznacza to, że możesz podać własną toJSON
metodę serializacji z logiką do serializacji obiektów niestandardowych. W ten sposób można szybko i łatwo utworzyć obsługę serializacji dla bardziej złożonych drzew obiektów.
<SELECT MULTIPLE>
io tej <INPUT type="checkbox">
samej nazwie, konwertując wartość na tablicę.
JSON.stringify(Object.fromEntries(formData));
jest o wiele przyjemniejsza
W 2019 roku tego rodzaju zadanie stało się super łatwe.
JSON.stringify(Object.fromEntries(formData));
Object.fromEntries
: Obsługiwane w Chrome 73+, Firefox 63+, Safari 12.1
<select multiple>
lub <input type="checkbox">
😞
JSON.stringify(Object.fromEntries(formData.entries()));
Oto sposób na zrobienie tego w bardziej funkcjonalnym stylu, bez korzystania z biblioteki.
Array.from(formData.entries()).reduce((memo, pair) => ({
...memo,
[pair[0]]: pair[1],
}), {});
Przykład:
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>
Jeśli masz wiele wpisów o tej samej nazwie, na przykład jeśli używasz <SELECT multiple>
lub masz wiele wpisów o tej samej nazwie, <INPUT type="checkbox">
musisz się tym zająć i utworzyć tablicę wartości. W przeciwnym razie otrzymasz tylko ostatnią wybraną wartość.
Oto nowoczesny wariant 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 );
}
Nieco starszy kod (ale nadal nie jest obsługiwany przez IE11, ponieważ nie obsługuje ForEach
ani nie jest entries
włączony 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 );
}
Można to osiągnąć za pomocą obiektu FormData () . Ten obiekt FormData zostanie wypełniony bieżącymi kluczami / wartościami formularza przy użyciu właściwości name każdego elementu dla kluczy i ich przesłanej wartości dla wartości. Zakoduje również zawartość wejściową pliku.
Przykład:
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())
Łatwa w użyciu funkcja
Stworzyłem do tego funkcję
function FormDataToJSON(FormElement){
var formData = new FormData(FormElement);
var ConvertedJSON= {};
for (const [key, value] of formData.entries())
{
ConvertedJSON[key] = value;
}
return ConvertedJSON
}
Przykładowe użycie
var ReceivedJSON = FormDataToJSON(document.getElementById('FormId');)
W tym kodzie utworzyłem pustą zmienną JSON za pomocą for
pętli. Użyłem key
s z obiektu formData do kluczy JSON w każdym Itration.
Ten kod znajdujesz w mojej bibliotece JS na GitHubie, zasugeruj mi, jeśli wymaga poprawy Umieściłem kod tutaj https://github.com/alijamal14/Utilities/blob/master/Utilities.js
<select multiple>
lub <input type="checkbox">
.
Ten post ma już rok ... ale naprawdę podoba mi się odpowiedź @dzuc w ES6. Jednak jest niekompletny, ponieważ nie był w stanie obsłużyć wielu wyborów lub pól wyboru. To już wskazywało i oferowano rozwiązania kodowe. Uważam, że są ciężkie i niezoptymalizowane. Napisałem więc 2 wersje w oparciu o @dzuc do obsługi tych przypadków:
let r=Array.from(fd).reduce(
(o , [k,v]) => (
(!o[k])
? {...o , [k] : v}
: {...o , [k] : [...o[k] , v]}
)
,{}
);
let obj=JSON.stringify(r);
Wersja One line Hotshot:
Array.from(fd).reduce((o,[k,v])=>((!o[k])?{...o,[k]:v}:{...o,[k]:[...o[k],v]}),{});
[]
sufiks.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);
Wersja One line 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}),{});
Od czasu, gdy ostatnio pisałem poprzedni drugi przypadek, w pracy zdarzyło się, że formularz PHP ma checkboxy na wielu poziomach. Napisałem nową sprawę, aby wspierać poprzednią sprawę i tę. Stworzyłem fragment, aby lepiej zaprezentować ten przypadek, wynik pokaż na konsoli dla tego demo, zmodyfikuj go do swoich potrzeb. Próbowałem zoptymalizować go najlepiej, jak mogłem, bez uszczerbku dla wydajności, jednak pogorszyło to czytelność dla ludzi. Wykorzystuje to, że tablice są obiektami, a zmienne wskazujące na tablice są zachowywane jako odniesienie. Nie ma gorącej odpowiedzi na to, bądź moim gościem.
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}), {});
wersja hotshot es2018
FormData .entries
i for of
wyrażenie nie są obsługiwane w przeglądarkach IE11 i Safari.
Oto prostsza wersja obsługująca Safari, Chrome, Firefox i Edge
function formDataToJSON(formElement) {
var formData = new FormData(formElement),
convertedJSON = {};
formData.forEach(function(value, key) {
convertedJSON[key] = value;
});
return convertedJSON;
}
Ostrzeżenie: ta odpowiedź nie działa w IE11.
FormData nie ma forEach
metody w IE11.
Wciąż szukam ostatecznego rozwiązania obsługującego wszystkie główne przeglądarki.
Jeśli potrzebujesz wsparcia dla serializacji pól zagnieżdżonych, podobnie jak PHP obsługuje pola formularzy, możesz użyć następującej funkcji
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>
Jeśli używasz lodash, można to zrobić zwięźle fromPairs
import {fromPairs} from 'lodash';
const object = fromPairs(Array.from(formData.entries()));
Możesz tego spróbować
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);
}
Chociaż odpowiedź od @dzuc jest już bardzo dobra, możesz użyć destrukturyzacji tablic (dostępne w nowoczesnych przeglądarkach lub z Babel), aby uczynić ją jeszcze bardziej elegancką:
// 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,
}), {})
Obraźliwa jedna linijka!
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});
Dzisiaj dowiedziałem się, że Firefox obsługuje rozprzestrzenianie obiektów i niszczenie tablic!
Jeśli poniższe elementy spełniają Twoje potrzeby, masz szczęście:
[['key','value1'], ['key2','value2']
(na przykład to, co daje FormData) na obiekt klucz-> wartość, taki jak {key1: 'value1', key2: 'value2'}
i przekonwertować go na ciąg JSON.Oto kod, którego będziesz potrzebować:
const data = new FormData(document.querySelector('form'));
const json = JSON.stringify(Array.from(data).reduce((o,[k,v])=>(o[k]=v,o),{}));
Mam nadzieję, że to komuś pomoże.
Jak dotąd nie widziałem wzmianek o metodzie FormData.getAll .
Oprócz zwracania wszystkich wartości skojarzonych z danym kluczem z obiektu FormData, staje się to naprawdę proste przy użyciu metody Object.fromEntries określonej przez innych tutaj.
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)
])
)
Fragment w akcji
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>
Myślę, że jest to najprostszy sposób na uzyskanie pożądanego wyniku z formData
obiektu FormData:
const jsonData = {};
for(const [key, value] of formData) {
jsonData[key] = value;
}
Pracował dla mnie
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>
lub<input type="checkbox">
W moim przypadku forma Data była danymi, baza ognia oczekiwała obiektu, ale dane zawierają obiekt i wszystkie inne rzeczy, więc spróbowałem data.value to zadziałało !!!
Spóźniam się tutaj. Jednak stworzyłem prostą metodę, która sprawdza typ wejściowy = "pole wyboru"
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);
Mam nadzieję, że to pomoże komuś innemu.
Możesz łatwo wykonać tę pracę, nie używając niczego specjalnego. Wystarczy kod podobny do poniższego.
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()
pomaga? Może próbujesz naprawić coś, co można zrobić w inny sposób?