Comment convertir un objet HTML5 FormData en JSON? Sans Jquery et gestion des propriétés imbriquées dans FormData comme un objet.
Comment convertir un objet HTML5 FormData en JSON? Sans Jquery et gestion des propriétés imbriquées dans FormData comme un objet.
Réponses:
Vous pouvez également utiliser directement forEach
sur l' FormData
objet:
var object = {};
formData.forEach(function(value, key){
object[key] = value;
});
var json = JSON.stringify(object);
Et pour ceux qui préfèrent la même solution avec les fonctions fléchées ES6 :
var object = {};
formData.forEach((value, key) => {object[key] = value});
var json = JSON.stringify(object);
Et pour ceux qui souhaitent prendre en charge les listes de sélection multiples ou d'autres éléments de formulaire avec plusieurs valeurs (car il y a tellement de commentaires sous la réponse concernant ce problème, j'ajouterai une solution possible) :
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);
Voici un Fiddle démontrant l'utilisation de cette méthode avec une simple liste de sélection multiple.
En guise de note supplémentaire pour ceux qui se retrouvent ici, si le but de la conversion des données du formulaire en json est de l'envoyer via une requête HTTP XML à un serveur, vous pouvez envoyer l' FormData
objet directement sans le convertir. Aussi simple que ceci:
var request = new XMLHttpRequest();
request.open("POST", "http://example.com/submitform.php");
request.send(formData);
Voir aussi Utilisation d'objets FormData sur MDN pour référence :
Comme mentionné dans l'un des commentaires ci-dessous ma réponse, la stringify
méthode JSON ne fonctionnera pas hors de la boîte pour tous les types d'objets. Pour plus d'informations sur les types pris en charge, je voudrais consulter la section Description de la documentation MDN deJSON.stringify
.
Dans la description, il est également mentionné que:
Si la valeur a une méthode toJSON (), il est responsable de définir les données qui seront sérialisées.
Cela signifie que vous pouvez fournir votre propre toJSON
méthode de sérialisation avec une logique de sérialisation de vos objets personnalisés. Ainsi, vous pouvez rapidement et facilement créer une prise en charge de la sérialisation pour des arborescences d'objets plus complexes.
<SELECT MULTIPLE>
et <INPUT type="checkbox">
avec le même nom, en convertissant la valeur en tableau.
JSON.stringify(Object.fromEntries(formData));
est tellement plus agréable
En 2019, ce genre de tâche est devenu super facile.
JSON.stringify(Object.fromEntries(formData));
Object.fromEntries
: Pris en charge dans Chrome 73+, Firefox 63+, Safari 12.1
<select multiple>
ou <input type="checkbox">
😞
JSON.stringify(Object.fromEntries(formData.entries()));
Voici une façon de le faire dans un style plus fonctionnel, sans utiliser de bibliothèque.
Array.from(formData.entries()).reduce((memo, pair) => ({
...memo,
[pair[0]]: pair[1],
}), {});
Exemple:
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>
Si vous avez plusieurs entrées avec le même nom, par exemple si vous utilisez <SELECT multiple>
ou en avez plusieurs <INPUT type="checkbox">
avec le même nom, vous devez vous en occuper et créer un tableau de la valeur. Sinon, vous n'obtiendrez que la dernière valeur sélectionnée.
Voici la variante ES6 moderne:
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 );
}
Code peu plus (mais toujours pas pris en charge par IE11, car il ne supporte pas ForEach
ou entries
sur 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 );
}
Vous pouvez y parvenir en utilisant l' objet FormData () . Cet objet FormData sera rempli avec les clés / valeurs actuelles du formulaire en utilisant la propriété name de chaque élément pour les clés et leur valeur soumise pour les valeurs. Il encodera également le contenu d'entrée du fichier.
Exemple:
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())
Fonction facile à utiliser
J'ai créé une fonction pour cela
function FormDataToJSON(FormElement){
var formData = new FormData(FormElement);
var ConvertedJSON= {};
for (const [key, value] of formData.entries())
{
ConvertedJSON[key] = value;
}
return ConvertedJSON
}
Exemple d'utilisation
var ReceivedJSON = FormDataToJSON(document.getElementById('FormId');)
Dans ce code, j'ai créé une variable JSON vide à l'aide d'une boucle.J'ai for
utilisé des key
s de l'objet formData aux clés JSON dans chaque Itration.
Vous trouvez ce code dans ma bibliothèque JS sur GitHub, suggérez-moi s'il a besoin d'amélioration, j'ai placé le code ici https://github.com/alijamal14/Utilities/blob/master/Utilities.js
<select multiple>
ou <input type="checkbox">
.
Ce message a déjà un an ... mais j'aime vraiment beaucoup la réponse ES6 @dzuc. Cependant, il est incomplet car il n'a pas été en mesure de gérer plusieurs sélections ou cases à cocher. Cela a déjà pointé et des solutions de code ont été proposées. Je les trouve lourds et non optimisés. J'ai donc écrit 2 versions basées sur @dzuc pour gérer ces cas:
let r=Array.from(fd).reduce(
(o , [k,v]) => (
(!o[k])
? {...o , [k] : v}
: {...o , [k] : [...o[k] , v]}
)
,{}
);
let obj=JSON.stringify(r);
Version Hotshot une ligne:
Array.from(fd).reduce((o,[k,v])=>((!o[k])?{...o,[k]:v}:{...o,[k]:[...o[k],v]}),{});
[]
suffixe.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);
Version Hotshot une ligne:
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}),{});
Depuis la dernière fois que j'ai écrit le deuxième cas précédent, au travail, il est arrivé que le formulaire PHP ait des cases à cocher sur plusieurs niveaux. J'ai écrit un nouveau cas pour soutenir le cas précédent et celui-ci. J'ai créé un extrait pour mieux mettre en valeur ce cas, le résultat affiché sur la console pour cette démo, modifiez-le selon vos besoins. J'ai essayé de l'optimiser du mieux que je pouvais sans compromettre les performances, mais cela compromettait une certaine lisibilité humaine. Il tire parti du fait que les tableaux sont des objets et que les variables pointant vers des tableaux sont conservées comme référence. Pas de hotshot pour celui-ci, soyez mon invité.
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 version es2018
La méthode FormData .entries
et l' for of
expression ne sont pas prises en charge dans IE11 et Safari.
Voici une version plus simple pour prendre en charge Safari, Chrome, Firefox et Edge
function formDataToJSON(formElement) {
var formData = new FormData(formElement),
convertedJSON = {};
formData.forEach(function(value, key) {
convertedJSON[key] = value;
});
return convertedJSON;
}
Attention: cette réponse ne fonctionne pas dans IE11.
FormData n'a pas de forEach
méthode dans IE11.
Je suis toujours à la recherche d'une solution finale pour prendre en charge tous les principaux navigateurs.
Si vous utilisez lodash, cela peut être fait de manière concise avec fromPairs
import {fromPairs} from 'lodash';
const object = fromPairs(Array.from(formData.entries()));
Si vous avez besoin de support pour la sérialisation des champs imbriqués, de la même manière que PHP gère les champs de formulaire, vous pouvez utiliser la fonction suivante
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>
Vous pouvez essayer ceci
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);
}
Même si la réponse de @dzuc est déjà très bonne, vous pouvez utiliser la déstructuration des tableaux (disponible dans les navigateurs modernes ou avec Babel) pour le rendre encore un peu plus élégant:
// 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,
}), {})
Une doublure abusive!
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});
Aujourd'hui, j'ai appris que Firefox prend en charge la diffusion d'objets et la déstructuration des tableaux!
Si les articles suivants répondent à vos besoins, vous avez de la chance:
[['key','value1'], ['key2','value2']
(comme ce que FormData vous donne) en un objet clé-> valeur comme {key1: 'value1', key2: 'value2'}
et le convertir en une chaîne JSON.Voici le code dont vous aurez besoin:
const data = new FormData(document.querySelector('form'));
const json = JSON.stringify(Array.from(data).reduce((o,[k,v])=>(o[k]=v,o),{}));
J'espère que cela aide quelqu'un.
Je n'ai vu aucune mention de la méthode FormData.getAll jusqu'à présent.
En plus de renvoyer toutes les valeurs associées à une clé donnée à partir d'un objet FormData, cela devient vraiment simple en utilisant la méthode Object.fromEntries comme spécifié par d'autres ici.
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)
])
)
Extrait en action
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>
A travaillé pour moi
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>
ou<input type="checkbox">
Dans mon cas, les données étaient des données, la base de feu attendait un objet mais les données contiennent un objet ainsi que tous les autres éléments, alors j'ai essayé data.value, cela a fonctionné !!!
J'arrive tard ici. Cependant, j'ai fait une méthode simple qui vérifie le type d'entrée = "case à cocher"
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);
J'espère que cela aide quelqu'un d'autre.
Vous pouvez faire ce travail facilement sans utiliser quoi que ce soit de spécial. Un code comme celui ci-dessous suffira.
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()
aide? Peut-être que vous essayez de réparer quelque chose qui pourrait être fait d'une autre manière?