Come convertire l'oggetto FormData HTML5 in JSON? Senza Jquery e la gestione delle proprietà nidificate in FormData come un oggetto.
Come convertire l'oggetto FormData HTML5 in JSON? Senza Jquery e la gestione delle proprietà nidificate in FormData come un oggetto.
Risposte:
Si potrebbe anche usare forEach
sul FormData
oggetto direttamente:
var object = {};
formData.forEach(function(value, key){
object[key] = value;
});
var json = JSON.stringify(object);
E per chi preferisce la stessa soluzione con le funzioni freccia ES6 :
var object = {};
formData.forEach((value, key) => {object[key] = value});
var json = JSON.stringify(object);
E per coloro che desiderano il supporto per elenchi di selezione multipla o altri elementi del modulo con più valori (poiché ci sono così tanti commenti sotto la risposta riguardo a questo problema, aggiungerò una possibile soluzione) :
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);
Qui un violino che dimostra l'uso di questo metodo con un semplice elenco di selezione multipla.
Come nota a margine per coloro che finiscono qui, nel caso in cui lo scopo della conversione dei dati del modulo in json sia di inviarlo tramite una richiesta HTTP XML a un server, è possibile inviare l' FormData
oggetto direttamente senza convertirlo. Semplice come questo:
var request = new XMLHttpRequest();
request.open("POST", "http://example.com/submitform.php");
request.send(formData);
Vedere anche Utilizzo di oggetti FormData su MDN per riferimento :
Come accennato in uno dei commenti sotto la mia risposta, il stringify
metodo JSON non funzionerà immediatamente per tutti i tipi di oggetti. Per ulteriori informazioni sui tipi supportati, fare riferimento alla sezione Descrizione nella documentazione MDN diJSON.stringify
.
Nella descrizione si dice anche che:
Se il valore ha un metodo toJSON (), è responsabile di definire quali dati verranno serializzati.
Ciò significa che è possibile fornire il proprio toJSON
metodo di serializzazione con logica per serializzare gli oggetti personalizzati. In questo modo è possibile creare rapidamente e facilmente il supporto della serializzazione per alberi di oggetti più complessi.
<SELECT MULTIPLE>
e <INPUT type="checkbox">
con lo stesso nome, convertendo il valore in un array.
JSON.stringify(Object.fromEntries(formData));
è molto più carina
Nel 2019, questo tipo di attività è diventato semplicissimo.
JSON.stringify(Object.fromEntries(formData));
Object.fromEntries
: Supportato in Chrome 73+, Firefox 63+, Safari 12.1
<select multiple>
o <input type="checkbox">
😞
JSON.stringify(Object.fromEntries(formData.entries()));
Ecco un modo per farlo in uno stile più funzionale, senza l'uso di una libreria.
Array.from(formData.entries()).reduce((memo, pair) => ({
...memo,
[pair[0]]: pair[1],
}), {});
Esempio:
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>
Se hai più voci con lo stesso nome, ad esempio se ne usi <SELECT multiple>
o ne hai più <INPUT type="checkbox">
con lo stesso nome, devi occupartene e creare un array del valore. Altrimenti ottieni solo l'ultimo valore selezionato.
Ecco la moderna variante 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 );
}
Codice leggermente più vecchio (ma ancora non supportato da IE11, poiché non supporta ForEach
o entries
attivaFormData
)
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 );
}
È possibile ottenere ciò utilizzando FormData () oggetto . Questo oggetto FormData verrà popolato con le chiavi / valori correnti del modulo utilizzando la proprietà name di ogni elemento per le chiavi e il valore inviato per i valori. Codificherà anche il contenuto di input del file.
Esempio:
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())
Funzione facile da usare
Ho creato una funzione per questo
function FormDataToJSON(FormElement){
var formData = new FormData(FormElement);
var ConvertedJSON= {};
for (const [key, value] of formData.entries())
{
ConvertedJSON[key] = value;
}
return ConvertedJSON
}
Utilizzo di esempio
var ReceivedJSON = FormDataToJSON(document.getElementById('FormId');)
In questo codice ho creato una variabile JSON vuota usando il for
loop che ho usato key
s da formData Object a JSON Keys in ogni Itration.
Trovi questo codice nella mia libreria JS su GitHub Suggeriscimi se ha bisogno di miglioramenti Ho inserito il codice qui https://github.com/alijamal14/Utilities/blob/master/Utilities.js
<select multiple>
o <input type="checkbox">
.
Questo post è già vecchio di un anno ... ma mi piace davvero molto la risposta di ES6 @dzuc. Tuttavia è incompleto perché non è stato possibile gestire più selezioni o caselle di controllo. Questo è già stato indicato e sono state offerte soluzioni di codice. Li trovo pesanti e non ottimizzati. Quindi ho scritto 2 versioni basate su @dzuc per gestire questi casi:
let r=Array.from(fd).reduce(
(o , [k,v]) => (
(!o[k])
? {...o , [k] : v}
: {...o , [k] : [...o[k] , v]}
)
,{}
);
let obj=JSON.stringify(r);
Versione Hotshot a una riga:
Array.from(fd).reduce((o,[k,v])=>((!o[k])?{...o,[k]:v}:{...o,[k]:[...o[k],v]}),{});
[]
suffisso.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);
Versione Hotshot a una riga:
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}),{});
Dall'ultima volta che ho scritto il secondo caso precedente, al lavoro si è verificato un caso in cui il modulo PHP ha caselle di controllo su più livelli. Ho scritto un nuovo caso per supportare il caso precedente e questo. Ho creato uno snippet per mostrare meglio questo caso, il risultato mostrato sulla console per questa demo, modificalo secondo le tue necessità. Ho cercato di ottimizzarlo il meglio che potevo senza compromettere le prestazioni, tuttavia, ha compromesso la leggibilità umana. Si avvantaggia del fatto che gli array sono oggetti e le variabili che puntano agli array vengono mantenute come riferimento. Nessun hotshot per questo, sii mio ospite.
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}), {});
versione hotshot es2018
Il metodo FormData .entries
e l' for of
espressione non sono supportati in IE11 e Safari.
Ecco una versione più semplice per supportare Safari, Chrome, Firefox e Edge
function formDataToJSON(formElement) {
var formData = new FormData(formElement),
convertedJSON = {};
formData.forEach(function(value, key) {
convertedJSON[key] = value;
});
return convertedJSON;
}
Attenzione: questa risposta non funziona in IE11.
FormData non dispone di un forEach
metodo in IE11.
Sto ancora cercando una soluzione finale per supportare tutti i principali browser.
Se stai usando lodash, puoi farlo in modo conciso fromPairs
import {fromPairs} from 'lodash';
const object = fromPairs(Array.from(formData.entries()));
Se hai bisogno di supporto per serializzare i campi nidificati, in modo simile a come PHP gestisce i campi modulo, puoi usare la seguente funzione
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>
Puoi provare questo
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);
}
Anche se la risposta di @dzuc è già molto buona, potresti usare la destrutturazione dell'array (disponibile nei browser moderni o con Babel) per renderlo ancora un po 'più elegante:
// 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,
}), {})
One-liner abusivo!
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});
Oggi ho appreso che Firefox supporta la diffusione degli oggetti e la destrutturazione degli array!
Se i seguenti elementi soddisfano le tue esigenze, sei fortunato:
[['key','value1'], ['key2','value2']
(come quello che ti dà FormData) in un oggetto chiave-> valore come {key1: 'value1', key2: 'value2'}
e convertirlo in una stringa JSON.Ecco il codice che ti servirà:
const data = new FormData(document.querySelector('form'));
const json = JSON.stringify(Array.from(data).reduce((o,[k,v])=>(o[k]=v,o),{}));
Spero che questo aiuti qualcuno.
Finora non ho visto menzioni del metodo FormData.getAll .
Oltre a restituire tutti i valori associati a una determinata chiave dall'interno di un oggetto FormData, diventa davvero semplice utilizzare il metodo Object.fromEntries come specificato da altri qui.
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 in azione
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>
Ha funzionato per me
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>
o<input type="checkbox">
Nel mio caso i dati erano dati, la base antincendio si aspettava un oggetto ma i dati contengono l'oggetto e tutte le altre cose, quindi ho provato data.value ha funzionato !!!
Arrivo tardi qui. Tuttavia, ho creato un metodo semplice che controlla il tipo di input = "casella di controllo"
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);
Spero che questo aiuti qualcun altro.
Puoi fare questo lavoro facilmente senza usare nulla di speciale. Un codice come quello qui sotto sarà sufficiente.
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()
aiuta? Forse cerchi di aggiustare qualcosa che può essere fatto in altro modo?